<!DOCTYPE html>
<html lang="en">
    <head hexo-theme='https://github.com/volantis-x/hexo-theme-volantis/#5.8.0'>
  <meta name="generator" content="Hexo 6.3.0">
  <meta name="Volantis" content="5.8.0">
  <meta charset="utf-8">
  <!-- SEO相关 -->
  
  <link rel="canonical" href="http://8.219.11.28/2024/02/23/前后端-spring框架课堂笔记/"/>
  <!-- 渲染优化 -->
    <meta http-equiv='x-dns-prefetch-control' content='on' />
      <link rel='dns-prefetch' href='https://unpkg.com'>
      <link rel="preconnect" href="https://unpkg.com" crossorigin>
  <meta name="renderer" content="webkit">
  <meta name="force-rendering" content="webkit">
  <meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1">
    <meta http-equiv="Content-Security-Policy" content=" default-src 'self' https:; block-all-mixed-content; base-uri 'self' https:; form-action 'self' https:; worker-src 'self' https:; connect-src 'self' https: *; img-src 'self' data: https: *; media-src 'self' https: *; font-src 'self' data: https: *; frame-src 'self' https: *; manifest-src 'self' https: *; child-src https:; script-src 'self' https: 'unsafe-inline' *; style-src 'self' https: 'unsafe-inline' *; ">
  <meta name="HandheldFriendly" content="True" >
  <meta name="apple-mobile-web-app-capable" content="yes">
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=5">
  <meta content="black-translucent" name="apple-mobile-web-app-status-bar-style">
  <meta content="telephone=no" name="format-detection">
  <!-- import head_begin begin -->
  <!-- import head_begin end -->
  <!-- Custom Files headBegin begin-->
  
  <!-- Custom Files headBegin end-->
  <!-- front-matter head_begin begin -->
  <!-- front-matter head_begin end -->
  <link rel="preload" href="/css/style.css" as="style">
  <link rel="preload" href="https://unpkg.com/volantis-static@0.0.1654736714924/media/fonts/VarelaRound/VarelaRound-Regular.ttf" as="font" type="font/ttf" crossorigin="anonymous">
<link rel="preload" href="https://unpkg.com/volantis-static@0.0.1654736714924/media/fonts/UbuntuMono/UbuntuMono-Regular.ttf" as="font" type="font/ttf" crossorigin="anonymous">

  <!-- feed -->
  <!-- 页面元数据 -->
  <title>欢迎来到我的个人博客~</title>
  <meta name="keywords" content="null">
  <meta desc name="description" content="这些技术大部分是自己总结的，非官方 - 天明 - 欢迎来到我的个人博客~">
  
<meta property="og:type" content="article">
<meta property="og:title" content="欢迎来到我的个人博客~">
<meta property="og:url" content="http://8.219.11.28/2024/02/23/%E5%89%8D%E5%90%8E%E7%AB%AF-Spring%E6%A1%86%E6%9E%B6%E8%AF%BE%E5%A0%82%E7%AC%94%E8%AE%B0/index.html">
<meta property="og:site_name" content="欢迎来到我的个人博客~">
<meta property="og:description" content="Spring框架课堂笔记Spring概述，ioC ， DI ，AOP ，整合JDBC ，事务管理 1. Spring概述1.1 什么是框架？框架（Framework）：框（指其约束性）架（指其支撑性），在软件设计中指为解决一个开放性问题而设计的具有一定约束性的支撑结构。在此结构上可以根据具体问题扩展、安插更多的组成部分，从而更迅速和方便地构建完整的解决问题的方案。  1、框架本身一般不完整到可以解">
<meta property="og:locale" content="en_US">
<meta property="og:image" content="https://unpkg.com/volantis-static@0.0.1654736714924/media/org.volantis/blog/favicon/android-chrome-192x192.png">
<meta property="article:published_time" content="2024-02-23T14:27:45.499Z">
<meta property="article:modified_time" content="2024-01-15T07:37:37.973Z">
<meta property="article:author" content="天明">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://unpkg.com/volantis-static@0.0.1654736714924/media/org.volantis/blog/favicon/android-chrome-192x192.png">
  <style>
    /* 首屏样式 */
    #safearea {
  display: none;
}
:root {
  --color-site-body: #f4f4f4;
  --color-site-bg: #f4f4f4;
  --color-site-inner: #fff;
  --color-site-footer: #666;
  --color-card: #fff;
  --color-text: #444;
  --color-block: #f6f6f6;
  --color-inlinecode: #c74f00;
  --color-codeblock: #fff7ea;
  --color-h1: #3a3a3a;
  --color-h2: #3a3a3a;
  --color-h3: #333;
  --color-h4: #444;
  --color-h5: #555;
  --color-h6: #666;
  --color-p: #444;
  --color-list: #666;
  --color-list-hl: #30ad91;
  --color-meta: #888;
  --color-read-bkg: #e0d8c8;
  --color-read-post: #f8f1e2;
  --color-copyright-bkg: #f5f5f5;
}
* {
  box-sizing: border-box;
  -webkit-box-sizing: border-box;
  -moz-box-sizing: border-box;
  outline: none;
  margin: 0;
  padding: 0;
}
*::-webkit-scrollbar {
  height: 4px;
  width: 4px;
}
*::-webkit-scrollbar-track-piece {
  background: transparent;
}
*::-webkit-scrollbar-thumb {
  background: #3dd9b6;
  cursor: pointer;
  border-radius: 2px;
  -webkit-border-radius: 2px;
}
*::-webkit-scrollbar-thumb:hover {
  background: #ff5722;
}
html {
  color: var(--color-text);
  width: 100%;
  height: 100%;
  font-family: UbuntuMono, "Varela Round", "PingFang SC", "Microsoft YaHei", Helvetica, Arial, Menlo, Monaco, monospace, sans-serif;
  font-size: 16px;
}
html >::-webkit-scrollbar {
  height: 4px;
  width: 4px;
}
html >::-webkit-scrollbar-track-piece {
  background: transparent;
}
html >::-webkit-scrollbar-thumb {
  background: #54b5a0 linear-gradient(45deg, rgba(255,255,255,0.4) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.4) 50%, rgba(255,255,255,0.4) 75%, transparent 75%, transparent);
  cursor: pointer;
  border-radius: 2px;
  -webkit-border-radius: 2px;
}
html >::-webkit-scrollbar-thumb:hover {
  background: #54b5a0 linear-gradient(45deg, rgba(255,255,255,0.4) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.4) 50%, rgba(255,255,255,0.4) 75%, transparent 75%, transparent);
}
body {
  background-color: var(--color-site-body);
  text-rendering: optimizelegibility;
  -webkit-tap-highlight-color: rgba(0,0,0,0);
  line-height: 1.6;
  -webkit-text-size-adjust: 100%;
  -ms-text-size-adjust: 100%;
}
body.modal-active {
  overflow: hidden;
}
@media screen and (max-width: 680px) {
  body.modal-active {
    position: fixed;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
  }
}
a {
  color: #2092ec;
  cursor: pointer;
  text-decoration: none;
  transition: all 0.28s ease;
  -webkit-transition: all 0.28s ease;
  -khtml-transition: all 0.28s ease;
  -moz-transition: all 0.28s ease;
  -o-transition: all 0.28s ease;
  -ms-transition: all 0.28s ease;
}
a:hover {
  color: #ff5722;
}
a:active,
a:hover {
  outline: 0;
}
ul,
ol {
  padding-left: 0;
}
ul li,
ol li {
  list-style: none;
}
header {
  display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
  display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
  display: block;
}
img {
  border: 0;
  background: none;
  max-width: 100%;
}
svg:not(:root) {
  overflow: hidden;
}
hr {
  -moz-box-sizing: content-box;
  box-sizing: content-box;
  -webkit-box-sizing: content-box;
  -moz-box-sizing: content-box;
  height: 0;
  border: 0;
  border-radius: 1px;
  -webkit-border-radius: 1px;
  border-bottom: 1px solid rgba(68,68,68,0.1);
}
button,
input {
  color: inherit;
  font: inherit;
  margin: 0;
}
button {
  overflow: visible;
  text-transform: none;
  -webkit-appearance: button;
  cursor: pointer;
}
@supports (backdrop-filter: blur(20px)) {
  .blur {
    background: rgba(255,255,255,0.9) !important;
    backdrop-filter: saturate(200%) blur(20px);
  }
}
.shadow {
  box-shadow: 0 1px 2px 0px rgba(0,0,0,0.1);
  -webkit-box-shadow: 0 1px 2px 0px rgba(0,0,0,0.1);
}
.shadow.floatable {
  transition: all 0.28s ease;
  -webkit-transition: all 0.28s ease;
  -khtml-transition: all 0.28s ease;
  -moz-transition: all 0.28s ease;
  -o-transition: all 0.28s ease;
  -ms-transition: all 0.28s ease;
}
.shadow.floatable:hover {
  box-shadow: 0 2px 4px 0px rgba(0,0,0,0.1), 0 4px 8px 0px rgba(0,0,0,0.1), 0 8px 16px 0px rgba(0,0,0,0.1);
  -webkit-box-shadow: 0 2px 4px 0px rgba(0,0,0,0.1), 0 4px 8px 0px rgba(0,0,0,0.1), 0 8px 16px 0px rgba(0,0,0,0.1);
}
#l_cover {
  min-height: 64px;
}
.cover-wrapper {
  top: 0;
  left: 0;
  max-width: 100%;
  height: 100vh;
  display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
  display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
  display: -ms-flexbox /* TWEENER - IE 10 */;
  display: -webkit-flex /* NEW - Chrome */;
  display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */;
  display: flex;
  flex-wrap: nowrap;
  -webkit-flex-wrap: nowrap;
  -khtml-flex-wrap: nowrap;
  -moz-flex-wrap: nowrap;
  -o-flex-wrap: nowrap;
  -ms-flex-wrap: nowrap;
  -webkit-box-direction: normal;
  -moz-box-direction: normal;
  -webkit-box-orient: vertical;
  -moz-box-orient: vertical;
  -webkit-flex-direction: column;
  -ms-flex-direction: column;
  flex-direction: column;
  align-items: center;
  align-self: center;
  align-content: center;
  color: var(--color-site-inner);
  padding: 0 16px;
  user-select: none;
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  position: relative;
  overflow: hidden;
  margin-bottom: -100px;
}
.cover-wrapper .cover-bg {
  position: absolute;
  width: 100%;
  height: 100%;
  background-position: center;
  background-size: cover;
  -webkit-background-size: cover;
  -moz-background-size: cover;
}
.cover-wrapper .cover-bg.lazyload:not(.loaded) {
  opacity: 0;
  -webkit-opacity: 0;
  -moz-opacity: 0;
}
.cover-wrapper .cover-bg.lazyload.loaded {
  animation-delay: 0s;
  animation-duration: 0.5s;
  animation-fill-mode: forwards;
  animation-timing-function: ease-out;
  animation-name: fadeIn;
}
@-moz-keyframes fadeIn {
  0% {
    opacity: 0;
    -webkit-opacity: 0;
    -moz-opacity: 0;
    filter: blur(12px);
    transform: scale(1.02);
    -webkit-transform: scale(1.02);
    -khtml-transform: scale(1.02);
    -moz-transform: scale(1.02);
    -o-transform: scale(1.02);
    -ms-transform: scale(1.02);
  }
  100% {
    opacity: 1;
    -webkit-opacity: 1;
    -moz-opacity: 1;
  }
}
@-webkit-keyframes fadeIn {
  0% {
    opacity: 0;
    -webkit-opacity: 0;
    -moz-opacity: 0;
    filter: blur(12px);
    transform: scale(1.02);
    -webkit-transform: scale(1.02);
    -khtml-transform: scale(1.02);
    -moz-transform: scale(1.02);
    -o-transform: scale(1.02);
    -ms-transform: scale(1.02);
  }
  100% {
    opacity: 1;
    -webkit-opacity: 1;
    -moz-opacity: 1;
  }
}
@-o-keyframes fadeIn {
  0% {
    opacity: 0;
    -webkit-opacity: 0;
    -moz-opacity: 0;
    filter: blur(12px);
    transform: scale(1.02);
    -webkit-transform: scale(1.02);
    -khtml-transform: scale(1.02);
    -moz-transform: scale(1.02);
    -o-transform: scale(1.02);
    -ms-transform: scale(1.02);
  }
  100% {
    opacity: 1;
    -webkit-opacity: 1;
    -moz-opacity: 1;
  }
}
@keyframes fadeIn {
  0% {
    opacity: 0;
    -webkit-opacity: 0;
    -moz-opacity: 0;
    filter: blur(12px);
    transform: scale(1.02);
    -webkit-transform: scale(1.02);
    -khtml-transform: scale(1.02);
    -moz-transform: scale(1.02);
    -o-transform: scale(1.02);
    -ms-transform: scale(1.02);
  }
  100% {
    opacity: 1;
    -webkit-opacity: 1;
    -moz-opacity: 1;
  }
}
.cover-wrapper .cover-body {
  z-index: 1;
  position: relative;
  width: 100%;
  height: 100%;
}
.cover-wrapper#full {
  height: calc(100vh + 100px);
  padding-bottom: 100px;
}
.cover-wrapper#half {
  max-height: 640px;
  min-height: 400px;
  height: calc(36vh - 64px + 200px);
}
.cover-wrapper #scroll-down {
  width: 100%;
  height: 64px;
  position: absolute;
  bottom: 100px;
  text-align: center;
  cursor: pointer;
}
.cover-wrapper #scroll-down .scroll-down-effects {
  color: #fff;
  font-size: 24px;
  line-height: 64px;
  position: absolute;
  width: 24px;
  left: calc(50% - 12px);
  text-shadow: 0 1px 2px rgba(0,0,0,0.1);
  animation: scroll-down-effect 1.5s infinite;
  -webkit-animation: scroll-down-effect 1.5s infinite;
  -khtml-animation: scroll-down-effect 1.5s infinite;
  -moz-animation: scroll-down-effect 1.5s infinite;
  -o-animation: scroll-down-effect 1.5s infinite;
  -ms-animation: scroll-down-effect 1.5s infinite;
}
@-moz-keyframes scroll-down-effect {
  0% {
    top: 0;
    opacity: 1;
    -webkit-opacity: 1;
    -moz-opacity: 1;
  }
  50% {
    top: -16px;
    opacity: 0.4;
    -webkit-opacity: 0.4;
    -moz-opacity: 0.4;
  }
  100% {
    top: 0;
    opacity: 1;
    -webkit-opacity: 1;
    -moz-opacity: 1;
  }
}
@-webkit-keyframes scroll-down-effect {
  0% {
    top: 0;
    opacity: 1;
    -webkit-opacity: 1;
    -moz-opacity: 1;
  }
  50% {
    top: -16px;
    opacity: 0.4;
    -webkit-opacity: 0.4;
    -moz-opacity: 0.4;
  }
  100% {
    top: 0;
    opacity: 1;
    -webkit-opacity: 1;
    -moz-opacity: 1;
  }
}
@-o-keyframes scroll-down-effect {
  0% {
    top: 0;
    opacity: 1;
    -webkit-opacity: 1;
    -moz-opacity: 1;
  }
  50% {
    top: -16px;
    opacity: 0.4;
    -webkit-opacity: 0.4;
    -moz-opacity: 0.4;
  }
  100% {
    top: 0;
    opacity: 1;
    -webkit-opacity: 1;
    -moz-opacity: 1;
  }
}
@keyframes scroll-down-effect {
  0% {
    top: 0;
    opacity: 1;
    -webkit-opacity: 1;
    -moz-opacity: 1;
  }
  50% {
    top: -16px;
    opacity: 0.4;
    -webkit-opacity: 0.4;
    -moz-opacity: 0.4;
  }
  100% {
    top: 0;
    opacity: 1;
    -webkit-opacity: 1;
    -moz-opacity: 1;
  }
}
.cover-wrapper .cover-body {
  margin-top: 64px;
  margin-bottom: 100px;
}
.cover-wrapper .cover-body,
.cover-wrapper .cover-body .top,
.cover-wrapper .cover-body .bottom {
  display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
  display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
  display: -ms-flexbox /* TWEENER - IE 10 */;
  display: -webkit-flex /* NEW - Chrome */;
  display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */;
  display: flex;
  -webkit-box-direction: normal;
  -moz-box-direction: normal;
  -webkit-box-orient: vertical;
  -moz-box-orient: vertical;
  -webkit-flex-direction: column;
  -ms-flex-direction: column;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  -webkit-justify-content: center;
  -khtml-justify-content: center;
  -moz-justify-content: center;
  -o-justify-content: center;
  -ms-justify-content: center;
  max-width: 100%;
}
.cover-wrapper .cover-body .bottom {
  margin-top: 32px;
}
.cover-wrapper .cover-body .title {
  font-family: "Varela Round", "PingFang SC", "Microsoft YaHei", Helvetica, Arial, Helvetica, monospace;
  font-size: 3.125rem;
  line-height: 1.2;
  text-shadow: 0 1px 2px rgba(0,0,0,0.1);
}
.cover-wrapper .cover-body .subtitle {
  font-size: 20px;
}
.cover-wrapper .cover-body .logo {
  max-height: 120px;
  max-width: calc(100% - 4 * 16px);
}
@media screen and (min-height: 1024px) {
  .cover-wrapper .cover-body .title {
    font-size: 3rem;
  }
  .cover-wrapper .cover-body .subtitle {
    font-size: 1.05rem;
  }
  .cover-wrapper .cover-body .logo {
    max-height: 150px;
  }
}
.cover-wrapper .cover-body .m_search {
  position: relative;
  max-width: calc(100% - 16px);
  width: 320px;
  vertical-align: middle;
}
.cover-wrapper .cover-body .m_search .form {
  position: relative;
  display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
  display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
  display: block;
  width: 100%;
}
.cover-wrapper .cover-body .m_search .icon,
.cover-wrapper .cover-body .m_search .input {
  transition: all 0.28s ease;
  -webkit-transition: all 0.28s ease;
  -khtml-transition: all 0.28s ease;
  -moz-transition: all 0.28s ease;
  -o-transition: all 0.28s ease;
  -ms-transition: all 0.28s ease;
}
.cover-wrapper .cover-body .m_search .icon {
  position: absolute;
  display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
  display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
  display: block;
  line-height: 2.5rem;
  width: 32px;
  top: 0;
  left: 5px;
  color: rgba(68,68,68,0.75);
}
.cover-wrapper .cover-body .m_search .input {
  display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
  display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
  display: block;
  height: 2.5rem;
  width: 100%;
  box-shadow: none;
  -webkit-box-shadow: none;
  box-sizing: border-box;
  -webkit-box-sizing: border-box;
  -moz-box-sizing: border-box;
  font-size: 0.875rem;
  -webkit-appearance: none;
  padding-left: 36px;
  border-radius: 1.4rem;
  -webkit-border-radius: 1.4rem;
  background: rgba(255,255,255,0.6);
  backdrop-filter: blur(10px);
  border: none;
  color: var(--color-text);
}
@media screen and (max-width: 500px) {
  .cover-wrapper .cover-body .m_search .input {
    padding-left: 36px;
  }
}
.cover-wrapper .cover-body .m_search .input:hover {
  background: rgba(255,255,255,0.8);
}
.cover-wrapper .cover-body .m_search .input:focus {
  background: #fff;
}
.cover-wrapper .list-h {
  display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
  display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
  display: -ms-flexbox /* TWEENER - IE 10 */;
  display: -webkit-flex /* NEW - Chrome */;
  display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */;
  display: flex;
  -webkit-box-direction: normal;
  -moz-box-direction: normal;
  -webkit-box-orient: horizontal;
  -moz-box-orient: horizontal;
  -webkit-flex-direction: row;
  -ms-flex-direction: row;
  flex-direction: row;
  flex-wrap: wrap;
  -webkit-flex-wrap: wrap;
  -khtml-flex-wrap: wrap;
  -moz-flex-wrap: wrap;
  -o-flex-wrap: wrap;
  -ms-flex-wrap: wrap;
  align-items: stretch;
  border-radius: 4px;
  -webkit-border-radius: 4px;
  user-select: none;
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
}
.cover-wrapper .list-h a {
  -webkit-box-flex: 1;
  -moz-box-flex: 1;
  -webkit-flex: 1 0;
  -ms-flex: 1 0;
  flex: 1 0;
  display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
  display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
  display: -ms-flexbox /* TWEENER - IE 10 */;
  display: -webkit-flex /* NEW - Chrome */;
  display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */;
  display: flex;
  font-weight: 600;
}
.cover-wrapper .list-h a img {
  display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
  display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
  display: block;
  border-radius: 2px;
  -webkit-border-radius: 2px;
  margin: 4px;
  min-width: 40px;
  max-width: 44px;
}
@media screen and (max-width: 768px) {
  .cover-wrapper .list-h a img {
    min-width: 36px;
    max-width: 40px;
  }
}
@media screen and (max-width: 500px) {
  .cover-wrapper .list-h a img {
    margin: 2px 4px;
    min-width: 32px;
    max-width: 36px;
  }
}
@media screen and (max-width: 375px) {
  .cover-wrapper .list-h a img {
    min-width: 28px;
    max-width: 32px;
  }
}
.cover-wrapper {
  max-width: 100%;
}
.cover-wrapper.search .bottom .menu {
  margin-top: 16px;
}
.cover-wrapper.search .bottom .menu .list-h a {
  white-space: nowrap;
  -webkit-box-direction: normal;
  -moz-box-direction: normal;
  -webkit-box-orient: horizontal;
  -moz-box-orient: horizontal;
  -webkit-flex-direction: row;
  -ms-flex-direction: row;
  flex-direction: row;
  align-items: baseline;
  padding: 2px;
  margin: 4px;
  color: var(--color-site-inner);
  opacity: 0.75;
  -webkit-opacity: 0.75;
  -moz-opacity: 0.75;
  text-shadow: 0 1px 2px rgba(0,0,0,0.05);
  border-bottom: 2px solid transparent;
}
.cover-wrapper.search .bottom .menu .list-h a i {
  margin-right: 4px;
}
.cover-wrapper.search .bottom .menu .list-h a p {
  font-size: 0.9375rem;
}
.cover-wrapper.search .bottom .menu .list-h a:hover,
.cover-wrapper.search .bottom .menu .list-h a.active,
.cover-wrapper.search .bottom .menu .list-h a:active {
  opacity: 1;
  -webkit-opacity: 1;
  -moz-opacity: 1;
  border-bottom: 2px solid var(--color-site-inner);
}
.cover-wrapper.dock .menu,
.cover-wrapper.featured .menu,
.cover-wrapper.focus .menu {
  border-radius: 6px;
  -webkit-border-radius: 6px;
}
.cover-wrapper.dock .menu .list-h a,
.cover-wrapper.featured .menu .list-h a,
.cover-wrapper.focus .menu .list-h a {
  -webkit-box-direction: normal;
  -moz-box-direction: normal;
  -webkit-box-orient: vertical;
  -moz-box-orient: vertical;
  -webkit-flex-direction: column;
  -ms-flex-direction: column;
  flex-direction: column;
  align-items: center;
  padding: 12px;
  line-height: 24px;
  border-radius: 4px;
  -webkit-border-radius: 4px;
  border-bottom: none;
  text-align: center;
  align-content: flex-end;
  color: rgba(68,68,68,0.7);
  font-size: 1.5rem;
}
@media screen and (max-width: 500px) {
  .cover-wrapper.dock .menu .list-h a,
  .cover-wrapper.featured .menu .list-h a,
  .cover-wrapper.focus .menu .list-h a {
    padding: 12px 8px;
  }
}
.cover-wrapper.dock .menu .list-h a i,
.cover-wrapper.featured .menu .list-h a i,
.cover-wrapper.focus .menu .list-h a i {
  margin: 8px;
}
.cover-wrapper.dock .menu .list-h a p,
.cover-wrapper.featured .menu .list-h a p,
.cover-wrapper.focus .menu .list-h a p {
  font-size: 0.875rem;
}
.cover-wrapper.dock .menu .list-h a.active,
.cover-wrapper.featured .menu .list-h a.active,
.cover-wrapper.focus .menu .list-h a.active {
  background: var(--color-card);
  backdrop-filter: none;
}
.cover-wrapper.dock .menu .list-h a.active i,
.cover-wrapper.featured .menu .list-h a.active i,
.cover-wrapper.focus .menu .list-h a.active i,
.cover-wrapper.dock .menu .list-h a.active i+p,
.cover-wrapper.featured .menu .list-h a.active i+p,
.cover-wrapper.focus .menu .list-h a.active i+p {
  color: #3dd9b6;
}
.cover-wrapper.dock .menu .list-h a.active img+p,
.cover-wrapper.featured .menu .list-h a.active img+p,
.cover-wrapper.focus .menu .list-h a.active img+p {
  color: var(--color-text);
}
.cover-wrapper.dock .menu .list-h a:hover,
.cover-wrapper.featured .menu .list-h a:hover,
.cover-wrapper.focus .menu .list-h a:hover {
  background: var(--color-card);
}
.cover-wrapper.dock .top {
  margin-bottom: 48px;
}
.cover-wrapper.dock .menu {
  background: rgba(255,255,255,0.5);
  position: absolute;
  bottom: 0;
  max-width: 100%;
}
.cover-wrapper.dock .menu .list-h {
  flex-wrap: nowrap;
  -webkit-flex-wrap: nowrap;
  -khtml-flex-wrap: nowrap;
  -moz-flex-wrap: nowrap;
  -o-flex-wrap: nowrap;
  -ms-flex-wrap: nowrap;
  margin: 4px;
}
.cover-wrapper.dock .menu .list-h a+a {
  margin-left: 4px;
}
@media screen and (max-width: 500px) {
  .cover-wrapper.dock .menu .list-h {
    overflow-x: scroll;
  }
  .cover-wrapper.dock .menu .list-h::-webkit-scrollbar {
    height: 0;
    width: 0;
  }
  .cover-wrapper.dock .menu .list-h::-webkit-scrollbar-track-piece {
    background: transparent;
  }
  .cover-wrapper.dock .menu .list-h::-webkit-scrollbar-thumb {
    background: #3dd9b6;
    cursor: pointer;
    border-radius: 0;
    -webkit-border-radius: 0;
  }
  .cover-wrapper.dock .menu .list-h::-webkit-scrollbar-thumb:hover {
    background: #ff5722;
  }
}
@supports (backdrop-filter: blur(20px)) {
  .cover-wrapper.dock .menu {
    background: rgba(255,255,255,0.5);
    backdrop-filter: saturate(200%) blur(20px);
  }
}
@font-face {
  font-family: 'UbuntuMono';
  src: url("https://unpkg.com/volantis-static@0.0.1654736714924/media/fonts/UbuntuMono/UbuntuMono-Regular.ttf");
  font-weight: 'normal';
  font-style: 'normal';
  font-display: swap;
}
@font-face {
  font-family: 'Varela Round';
  src: url("https://unpkg.com/volantis-static@0.0.1654736714924/media/fonts/VarelaRound/VarelaRound-Regular.ttf");
  font-weight: 'normal';
  font-style: 'normal';
  font-display: swap;
}
.l_header {
  position: fixed;
  z-index: 1000;
  top: 0;
  width: 100%;
  height: 64px;
  background: var(--color-card);
  box-shadow: 0 1px 2px 0px rgba(0,0,0,0.1);
  -webkit-box-shadow: 0 1px 2px 0px rgba(0,0,0,0.1);
}
.l_header.auto {
  transition: opacity 0.4s ease;
  -webkit-transition: opacity 0.4s ease;
  -khtml-transition: opacity 0.4s ease;
  -moz-transition: opacity 0.4s ease;
  -o-transition: opacity 0.4s ease;
  -ms-transition: opacity 0.4s ease;
  visibility: hidden;
}
.l_header.auto.show {
  opacity: 1 !important;
  -webkit-opacity: 1 !important;
  -moz-opacity: 1 !important;
  visibility: visible;
}
.l_header .container {
  margin-left: 16px;
  margin-right: 16px;
}
.l_header #wrapper {
  height: 100%;
  user-select: none;
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
}
.l_header #wrapper .nav-main,
.l_header #wrapper .nav-sub {
  display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
  display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
  display: -ms-flexbox /* TWEENER - IE 10 */;
  display: -webkit-flex /* NEW - Chrome */;
  display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */;
  display: flex;
  flex-wrap: nowrap;
  -webkit-flex-wrap: nowrap;
  -khtml-flex-wrap: nowrap;
  -moz-flex-wrap: nowrap;
  -o-flex-wrap: nowrap;
  -ms-flex-wrap: nowrap;
  justify-content: space-between;
  -webkit-justify-content: space-between;
  -khtml-justify-content: space-between;
  -moz-justify-content: space-between;
  -o-justify-content: space-between;
  -ms-justify-content: space-between;
  align-items: center;
}
.l_header #wrapper .nav-main {
  transition: all 0.28s ease;
  -webkit-transition: all 0.28s ease;
  -khtml-transition: all 0.28s ease;
  -moz-transition: all 0.28s ease;
  -o-transition: all 0.28s ease;
  -ms-transition: all 0.28s ease;
}
.l_header #wrapper.sub .nav-main {
  transform: translateY(-64px);
  -webkit-transform: translateY(-64px);
  -khtml-transform: translateY(-64px);
  -moz-transform: translateY(-64px);
  -o-transform: translateY(-64px);
  -ms-transform: translateY(-64px);
}
.l_header #wrapper .nav-sub {
  transition: all 0.28s ease;
  -webkit-transition: all 0.28s ease;
  -khtml-transition: all 0.28s ease;
  -moz-transition: all 0.28s ease;
  -o-transition: all 0.28s ease;
  -ms-transition: all 0.28s ease;
  opacity: 0;
  -webkit-opacity: 0;
  -moz-opacity: 0;
  height: 64px;
  width: calc(100% - 2 * 16px);
  position: absolute;
}
.l_header #wrapper .nav-sub ::-webkit-scrollbar {
  display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
  display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
  display: none;
}
@media screen and (min-width: 2048px) {
  .l_header #wrapper .nav-sub {
    max-width: 55vw;
    margin: auto;
  }
}
.l_header #wrapper.sub .nav-sub {
  opacity: 1;
  -webkit-opacity: 1;
  -moz-opacity: 1;
}
.l_header #wrapper .title {
  position: relative;
  color: var(--color-text);
  padding-left: 24px;
  max-height: 64px;
}
.l_header #wrapper .nav-main .title {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  flex-shrink: 0;
  line-height: 64px;
  padding: 0 24px;
  font-size: 1.25rem;
  font-family: "Varela Round", "PingFang SC", "Microsoft YaHei", Helvetica, Arial, Helvetica, monospace;
}
.l_header #wrapper .nav-main .title img {
  height: 64px;
}
.l_header .nav-sub {
  max-width: 1080px;
  margin: auto;
}
.l_header .nav-sub .title {
  font-weight: bold;
  font-family: UbuntuMono, "Varela Round", "PingFang SC", "Microsoft YaHei", Helvetica, Arial, Menlo, Monaco, monospace, sans-serif;
  line-height: 1.2;
  max-height: 64px;
  white-space: normal;
  flex-shrink: 1;
}
.l_header .switcher {
  display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
  display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
  display: none;
  line-height: 64px;
  align-items: center;
}
.l_header .switcher .s-toc {
  display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
  display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
  display: none;
}
@media screen and (max-width: 768px) {
  .l_header .switcher .s-toc {
    display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
    display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
    display: -ms-flexbox /* TWEENER - IE 10 */;
    display: -webkit-flex /* NEW - Chrome */;
    display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */;
    display: flex;
  }
}
.l_header .switcher >li {
  height: 48px;
  transition: all 0.28s ease;
  -webkit-transition: all 0.28s ease;
  -khtml-transition: all 0.28s ease;
  -moz-transition: all 0.28s ease;
  -o-transition: all 0.28s ease;
  -ms-transition: all 0.28s ease;
  margin: 2px;
}
@media screen and (max-width: 500px) {
  .l_header .switcher >li {
    margin: 0 1px;
    height: 48px;
  }
}
.l_header .switcher >li >a {
  display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
  display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
  display: -ms-flexbox /* TWEENER - IE 10 */;
  display: -webkit-flex /* NEW - Chrome */;
  display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */;
  display: flex;
  justify-content: center;
  -webkit-justify-content: center;
  -khtml-justify-content: center;
  -moz-justify-content: center;
  -o-justify-content: center;
  -ms-justify-content: center;
  align-items: center;
  width: 48px;
  height: 48px;
  padding: 0.85em 1.1em;
  border-radius: 100px;
  -webkit-border-radius: 100px;
  border: none;
  transition: all 0.28s ease;
  -webkit-transition: all 0.28s ease;
  -khtml-transition: all 0.28s ease;
  -moz-transition: all 0.28s ease;
  -o-transition: all 0.28s ease;
  -ms-transition: all 0.28s ease;
  color: #3dd9b6;
}
.l_header .switcher >li >a:hover {
  border: none;
}
.l_header .switcher >li >a.active,
.l_header .switcher >li >a:active {
  border: none;
  background: var(--color-site-bg);
}
@media screen and (max-width: 500px) {
  .l_header .switcher >li >a {
    width: 36px;
    height: 48px;
  }
}
.l_header .nav-sub .switcher {
  display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
  display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
  display: -ms-flexbox /* TWEENER - IE 10 */;
  display: -webkit-flex /* NEW - Chrome */;
  display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */;
  display: flex;
}
.l_header .m_search {
  display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
  display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
  display: -ms-flexbox /* TWEENER - IE 10 */;
  display: -webkit-flex /* NEW - Chrome */;
  display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */;
  display: flex;
  height: 64px;
  width: 240px;
  transition: all 0.28s ease;
  -webkit-transition: all 0.28s ease;
  -khtml-transition: all 0.28s ease;
  -moz-transition: all 0.28s ease;
  -o-transition: all 0.28s ease;
  -ms-transition: all 0.28s ease;
}
@media screen and (max-width: 1024px) {
  .l_header .m_search {
    width: 44px;
    min-width: 44px;
  }
  .l_header .m_search input::placeholder {
    opacity: 0;
    -webkit-opacity: 0;
    -moz-opacity: 0;
  }
  .l_header .m_search:hover {
    width: 240px;
  }
  .l_header .m_search:hover input::placeholder {
    opacity: 1;
    -webkit-opacity: 1;
    -moz-opacity: 1;
  }
}
@media screen and (min-width: 500px) {
  .l_header .m_search:hover .input {
    width: 100%;
  }
  .l_header .m_search:hover .input::placeholder {
    opacity: 1;
    -webkit-opacity: 1;
    -moz-opacity: 1;
  }
}
@media screen and (max-width: 500px) {
  .l_header .m_search {
    min-width: 0;
  }
  .l_header .m_search input::placeholder {
    opacity: 1;
    -webkit-opacity: 1;
    -moz-opacity: 1;
  }
}
.l_header .m_search .form {
  position: relative;
  display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
  display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
  display: -ms-flexbox /* TWEENER - IE 10 */;
  display: -webkit-flex /* NEW - Chrome */;
  display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */;
  display: flex;
  width: 100%;
  align-items: center;
}
.l_header .m_search .icon {
  position: absolute;
  width: 36px;
  left: 5px;
  color: var(--color-meta);
}
@media screen and (max-width: 500px) {
  .l_header .m_search .icon {
    display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
    display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
    display: none;
  }
}
.l_header .m_search .input {
  display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
  display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
  display: block;
  padding-top: 8px;
  padding-bottom: 8px;
  line-height: 1.3;
  width: 100%;
  color: var(--color-text);
  background: #fafafa;
  box-shadow: none;
  -webkit-box-shadow: none;
  box-sizing: border-box;
  -webkit-box-sizing: border-box;
  -moz-box-sizing: border-box;
  padding-left: 40px;
  font-size: 0.875rem;
  border-radius: 8px;
  -webkit-border-radius: 8px;
  border: none;
  transition: all 0.28s ease;
  -webkit-transition: all 0.28s ease;
  -khtml-transition: all 0.28s ease;
  -moz-transition: all 0.28s ease;
  -o-transition: all 0.28s ease;
  -ms-transition: all 0.28s ease;
}
@media screen and (min-width: 500px) {
  .l_header .m_search .input:focus {
    box-shadow: 0 4px 8px 0px rgba(0,0,0,0.1);
    -webkit-box-shadow: 0 4px 8px 0px rgba(0,0,0,0.1);
  }
}
@media screen and (max-width: 500px) {
  .l_header .m_search .input {
    background: var(--color-block);
    padding-left: 8px;
    border: none;
  }
  .l_header .m_search .input:hover,
  .l_header .m_search .input:focus {
    border: none;
  }
}
@media (max-width: 500px) {
  .l_header .m_search {
    left: 0;
    width: 0;
    overflow: hidden;
    position: absolute;
    background: #fff;
    transition: all 0.28s ease;
    -webkit-transition: all 0.28s ease;
    -khtml-transition: all 0.28s ease;
    -moz-transition: all 0.28s ease;
    -o-transition: all 0.28s ease;
    -ms-transition: all 0.28s ease;
  }
  .l_header .m_search .input {
    border-radius: 32px;
    -webkit-border-radius: 32px;
    margin-left: 16px;
    padding-left: 16px;
  }
  .l_header.z_search-open .m_search {
    width: 100%;
  }
  .l_header.z_search-open .m_search .input {
    width: calc(100% - 120px);
  }
}
ul.m-pc >li>a {
  color: inherit;
  border-bottom: 2px solid transparent;
}
ul.m-pc >li>a:active,
ul.m-pc >li>a.active {
  border-bottom: 2px solid #3dd9b6;
}
ul.m-pc li:hover >ul.list-v,
ul.list-v li:hover >ul.list-v {
  display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
  display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
  display: block;
}
ul.nav-list-h {
  display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
  display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
  display: -ms-flexbox /* TWEENER - IE 10 */;
  display: -webkit-flex /* NEW - Chrome */;
  display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */;
  display: flex;
  align-items: stretch;
}
ul.nav-list-h>li {
  position: relative;
  justify-content: center;
  -webkit-justify-content: center;
  -khtml-justify-content: center;
  -moz-justify-content: center;
  -o-justify-content: center;
  -ms-justify-content: center;
  height: 100%;
  line-height: 2.4;
  border-radius: 4px;
  -webkit-border-radius: 4px;
}
ul.nav-list-h>li >a {
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  font-weight: 600;
}
ul.list-v {
  z-index: 1;
  display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
  display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
  display: none;
  position: absolute;
  background: var(--color-card);
  box-shadow: 0 2px 4px 0px rgba(0,0,0,0.08), 0 4px 8px 0px rgba(0,0,0,0.08), 0 8px 16px 0px rgba(0,0,0,0.08);
  -webkit-box-shadow: 0 2px 4px 0px rgba(0,0,0,0.08), 0 4px 8px 0px rgba(0,0,0,0.08), 0 8px 16px 0px rgba(0,0,0,0.08);
  margin-top: -6px;
  border-radius: 4px;
  -webkit-border-radius: 4px;
  padding: 8px 0;
}
ul.list-v.show {
  display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
  display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
  display: block;
}
ul.list-v hr {
  margin-top: 8px;
  margin-bottom: 8px;
}
ul.list-v >li {
  white-space: nowrap;
  word-break: keep-all;
}
ul.list-v >li.header {
  font-size: 0.78125rem;
  font-weight: bold;
  line-height: 2em;
  color: var(--color-meta);
  margin: 8px 16px 4px;
}
ul.list-v >li.header i {
  margin-right: 8px;
}
ul.list-v >li ul {
  margin-left: 0;
  display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
  display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
  display: none;
  margin-top: -40px;
}
ul.list-v .aplayer-container {
  min-height: 64px;
  padding: 6px 16px;
}
ul.list-v >li>a {
  transition: all 0.28s ease;
  -webkit-transition: all 0.28s ease;
  -khtml-transition: all 0.28s ease;
  -moz-transition: all 0.28s ease;
  -o-transition: all 0.28s ease;
  -ms-transition: all 0.28s ease;
  display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
  display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
  display: block;
  color: var(--color-list);
  font-size: 0.875rem;
  font-weight: bold;
  line-height: 36px;
  padding: 0 20px 0 16px;
  text-overflow: ellipsis;
  margin: 0 4px;
  border-radius: 4px;
  -webkit-border-radius: 4px;
}
@media screen and (max-width: 1024px) {
  ul.list-v >li>a {
    line-height: 40px;
  }
}
ul.list-v >li>a >i {
  margin-right: 8px;
}
ul.list-v >li>a:active,
ul.list-v >li>a.active {
  color: var(--color-list-hl);
}
ul.list-v >li>a:hover {
  color: var(--color-list-hl);
  background: var(--color-site-bg);
}
.l_header .menu >ul>li>a {
  display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
  display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
  display: block;
  padding: 0 8px;
}
.l_header .menu >ul>li>a >i {
  margin-right: 4px;
}
.l_header ul.nav-list-h>li {
  color: var(--color-list);
  line-height: 64px;
}
.l_header ul.nav-list-h>li >a {
  max-height: 64px;
  overflow: hidden;
  color: inherit;
}
.l_header ul.nav-list-h>li >a:active,
.l_header ul.nav-list-h>li >a.active {
  color: #3dd9b6;
}
.l_header ul.nav-list-h>li:hover>a {
  color: var(--color-list-hl);
}
.l_header ul.nav-list-h>li i.music {
  animation: rotate-effect 1.5s linear infinite;
  -webkit-animation: rotate-effect 1.5s linear infinite;
  -khtml-animation: rotate-effect 1.5s linear infinite;
  -moz-animation: rotate-effect 1.5s linear infinite;
  -o-animation: rotate-effect 1.5s linear infinite;
  -ms-animation: rotate-effect 1.5s linear infinite;
}
@-moz-keyframes rotate-effect {
  0% {
    transform: rotate(0);
    -webkit-transform: rotate(0);
    -khtml-transform: rotate(0);
    -moz-transform: rotate(0);
    -o-transform: rotate(0);
    -ms-transform: rotate(0);
  }
  25% {
    transform: rotate(90deg);
    -webkit-transform: rotate(90deg);
    -khtml-transform: rotate(90deg);
    -moz-transform: rotate(90deg);
    -o-transform: rotate(90deg);
    -ms-transform: rotate(90deg);
  }
  50% {
    transform: rotate(180deg);
    -webkit-transform: rotate(180deg);
    -khtml-transform: rotate(180deg);
    -moz-transform: rotate(180deg);
    -o-transform: rotate(180deg);
    -ms-transform: rotate(180deg);
  }
  75% {
    transform: rotate(270deg);
    -webkit-transform: rotate(270deg);
    -khtml-transform: rotate(270deg);
    -moz-transform: rotate(270deg);
    -o-transform: rotate(270deg);
    -ms-transform: rotate(270deg);
  }
  100% {
    transform: rotate(360deg);
    -webkit-transform: rotate(360deg);
    -khtml-transform: rotate(360deg);
    -moz-transform: rotate(360deg);
    -o-transform: rotate(360deg);
    -ms-transform: rotate(360deg);
  }
}
@-webkit-keyframes rotate-effect {
  0% {
    transform: rotate(0);
    -webkit-transform: rotate(0);
    -khtml-transform: rotate(0);
    -moz-transform: rotate(0);
    -o-transform: rotate(0);
    -ms-transform: rotate(0);
  }
  25% {
    transform: rotate(90deg);
    -webkit-transform: rotate(90deg);
    -khtml-transform: rotate(90deg);
    -moz-transform: rotate(90deg);
    -o-transform: rotate(90deg);
    -ms-transform: rotate(90deg);
  }
  50% {
    transform: rotate(180deg);
    -webkit-transform: rotate(180deg);
    -khtml-transform: rotate(180deg);
    -moz-transform: rotate(180deg);
    -o-transform: rotate(180deg);
    -ms-transform: rotate(180deg);
  }
  75% {
    transform: rotate(270deg);
    -webkit-transform: rotate(270deg);
    -khtml-transform: rotate(270deg);
    -moz-transform: rotate(270deg);
    -o-transform: rotate(270deg);
    -ms-transform: rotate(270deg);
  }
  100% {
    transform: rotate(360deg);
    -webkit-transform: rotate(360deg);
    -khtml-transform: rotate(360deg);
    -moz-transform: rotate(360deg);
    -o-transform: rotate(360deg);
    -ms-transform: rotate(360deg);
  }
}
@-o-keyframes rotate-effect {
  0% {
    transform: rotate(0);
    -webkit-transform: rotate(0);
    -khtml-transform: rotate(0);
    -moz-transform: rotate(0);
    -o-transform: rotate(0);
    -ms-transform: rotate(0);
  }
  25% {
    transform: rotate(90deg);
    -webkit-transform: rotate(90deg);
    -khtml-transform: rotate(90deg);
    -moz-transform: rotate(90deg);
    -o-transform: rotate(90deg);
    -ms-transform: rotate(90deg);
  }
  50% {
    transform: rotate(180deg);
    -webkit-transform: rotate(180deg);
    -khtml-transform: rotate(180deg);
    -moz-transform: rotate(180deg);
    -o-transform: rotate(180deg);
    -ms-transform: rotate(180deg);
  }
  75% {
    transform: rotate(270deg);
    -webkit-transform: rotate(270deg);
    -khtml-transform: rotate(270deg);
    -moz-transform: rotate(270deg);
    -o-transform: rotate(270deg);
    -ms-transform: rotate(270deg);
  }
  100% {
    transform: rotate(360deg);
    -webkit-transform: rotate(360deg);
    -khtml-transform: rotate(360deg);
    -moz-transform: rotate(360deg);
    -o-transform: rotate(360deg);
    -ms-transform: rotate(360deg);
  }
}
@keyframes rotate-effect {
  0% {
    transform: rotate(0);
    -webkit-transform: rotate(0);
    -khtml-transform: rotate(0);
    -moz-transform: rotate(0);
    -o-transform: rotate(0);
    -ms-transform: rotate(0);
  }
  25% {
    transform: rotate(90deg);
    -webkit-transform: rotate(90deg);
    -khtml-transform: rotate(90deg);
    -moz-transform: rotate(90deg);
    -o-transform: rotate(90deg);
    -ms-transform: rotate(90deg);
  }
  50% {
    transform: rotate(180deg);
    -webkit-transform: rotate(180deg);
    -khtml-transform: rotate(180deg);
    -moz-transform: rotate(180deg);
    -o-transform: rotate(180deg);
    -ms-transform: rotate(180deg);
  }
  75% {
    transform: rotate(270deg);
    -webkit-transform: rotate(270deg);
    -khtml-transform: rotate(270deg);
    -moz-transform: rotate(270deg);
    -o-transform: rotate(270deg);
    -ms-transform: rotate(270deg);
  }
  100% {
    transform: rotate(360deg);
    -webkit-transform: rotate(360deg);
    -khtml-transform: rotate(360deg);
    -moz-transform: rotate(360deg);
    -o-transform: rotate(360deg);
    -ms-transform: rotate(360deg);
  }
}
.menu-phone li ul.list-v {
  right: calc(100% - 0.5 * 16px);
}
.menu-phone li ul.list-v ul {
  right: calc(100% - 0.5 * 16px);
}
#wrapper {
  max-width: 1080px;
  margin: auto;
}
@media screen and (min-width: 2048px) {
  #wrapper {
    max-width: 55vw;
  }
}
#wrapper .menu {
  -webkit-box-flex: 1;
  -moz-box-flex: 1;
  -webkit-flex: 1 1;
  -ms-flex: 1 1;
  flex: 1 1;
  margin: 0 16px 0 0;
}
#wrapper .menu .list-v ul {
  left: calc(100% - 0.5 * 16px);
}
.menu-phone {
  display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
  display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
  display: none;
  margin-top: 16px;
  right: 8px;
  transition: all 0.28s ease;
  -webkit-transition: all 0.28s ease;
  -khtml-transition: all 0.28s ease;
  -moz-transition: all 0.28s ease;
  -o-transition: all 0.28s ease;
  -ms-transition: all 0.28s ease;
}
.menu-phone ul {
  right: calc(100% - 0.5 * 16px);
}
@media screen and (max-width: 500px) {
  .menu-phone {
    display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
    display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
    display: block;
  }
}
.l_header {
  max-width: 65vw;
  left: calc((100% - 65vw) * 0.5);
  border-bottom-left-radius: 8px;
  border-bottom-right-radius: 8px;
}
@media screen and (max-width: 2048px) {
  .l_header {
    max-width: 1112px;
    left: calc((100% - 1112px) * 0.5);
  }
}
@media screen and (max-width: 1112px) {
  .l_header {
    left: 0;
    border-radius: 0;
    -webkit-border-radius: 0;
    max-width: 100%;
  }
}
@media screen and (max-width: 500px) {
  .l_header .container {
    margin-left: 0;
    margin-right: 0;
  }
  .l_header #wrapper .nav-main .title {
    padding-left: 16px;
    padding-right: 16px;
  }
  .l_header #wrapper .nav-sub {
    width: 100%;
  }
  .l_header #wrapper .nav-sub .title {
    overflow-y: scroll;
    margin-top: 2px;
    padding: 8px 16px;
  }
  .l_header #wrapper .switcher {
    display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
    display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
    display: -ms-flexbox /* TWEENER - IE 10 */;
    display: -webkit-flex /* NEW - Chrome */;
    display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */;
    display: flex;
    margin-right: 8px;
  }
  .l_header .menu {
    display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
    display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
    display: none;
  }
}
@media screen and (max-width: 500px) {
  .list-v li {
    max-width: 270px;
  }
}
#u-search {
  display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
  display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
  display: none;
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  padding: 60px 20px;
  z-index: 1001;
}
@media screen and (max-width: 680px) {
  #u-search {
    padding: 0px;
  }
}

  </style>
  <link rel="stylesheet" href="/css/style.css" media="print" onload="this.media='all';this.onload=null">
  <noscript><link rel="stylesheet" href="/css/style.css"></noscript>
  
<script>
if (/*@cc_on!@*/false || (!!window.MSInputMethodContext && !!document.documentMode))
    document.write(
	'<style>'+
		'html{'+
			'overflow-x: hidden !important;'+
			'overflow-y: hidden !important;'+
		'}'+
		'.kill-ie{'+
			'text-align:center;'+
			'height: 100%;'+
			'margin-top: 15%;'+
			'margin-bottom: 5500%;'+
		'}'+
    '.kill-t{'+
      'font-size: 2rem;'+
    '}'+
    '.kill-c{'+
      'font-size: 1.2rem;'+
    '}'+
		'#l_header,#l_body{'+
			'display: none;'+
		'}'+
	'</style>'+
    '<div class="kill-ie">'+
        `<span class="kill-t"><b>Sorry, your browser cannot access this site</b></span><br/>`+
        `<span class="kill-c">Microsoft has terminated support for Internet Explorer (IE) 10 and earlier versions in 2016. <br/>There are great security risks to continue using it. Please use contemporary mainstream browsers to access.</span><br/>`+
        `<a target="_blank" rel="noopener" href="https://blogs.windows.com/windowsexperience/2021/05/19/the-future-of-internet-explorer-on-windows-10-is-in-microsoft-edge/"><strong>Learn more ></strong></a>`+
    '</div>');
</script>


<noscript>
	<style>
		html{
			overflow-x: hidden !important;
			overflow-y: hidden !important;
		}
		.kill-noscript{
			text-align:center;
			height: 100%;
			margin-top: 15%;
			margin-bottom: 5500%;
		}
    .kill-t{
      font-size: 2rem;
    }
    .kill-c{
      font-size: 1.2rem;
    }
		#l_header,#l_body{
			display: none;
		}
	</style>
    <div class="kill-noscript">
        <span class="kill-t"><b>Sorry, your browser cannot access this site</b></span><br/>
        <span class="kill-c">This page requires browser support (enable) JavaScript</span><br/>
        <a target="_blank" rel="noopener" href="https://www.baidu.com/s?wd=启用JavaScript"><strong>Learn more ></strong></a>
    </div>
</noscript>


  <script>
  /************这个文件存放不需要重载的全局变量和全局函数*********/
  window.volantis = {}; // volantis 全局变量
  volantis.debug = "env"; // 调试模式
  volantis.dom = {}; // 页面Dom see: /source/js/app.js etc.

  volantis.GLOBAL_CONFIG ={
    debug: "env",
    cdn: {"js":{"app":"/js/app.js","parallax":"/js/plugins/parallax.js","rightMenu":"/js/plugins/rightMenu.js","rightMenus":"/js/plugins/rightMenus.js","sites":"/js/plugins/tags/sites.js","friends":"/js/plugins/tags/friends.js","contributors":"/js/plugins/tags/contributors.js","search":"/js/search/hexo.js"},"css":{"style":"/css/style.css"}},
    default: {"avatar":"https://unpkg.com/volantis-static@0.0.1654736714924/media/placeholder/avatar/round/3442075.svg","link":"https://unpkg.com/volantis-static@0.0.1654736714924/media/placeholder/link/8f277b4ee0ecd.svg","cover":"https://unpkg.com/volantis-static@0.0.1654736714924/media/placeholder/cover/76b86c0226ffd.svg","image":"https://unpkg.com/volantis-static@0.0.1654736714924/media/placeholder/image/2659360.svg"},
    lastupdate: new Date(1708699590610),
    sidebar: {
      for_page: ["blogger","category","tagcloud","donate"],
      for_post: ["toc"],
      webinfo: {
        lastupd: {
          enable: true,
          friendlyShow: true
        },
        runtime: {
          data: "2020/01/01",
          unit: "天"
        }
      }
    },
    plugins: {
      message: {"enable":true,"css":"https://unpkg.com/volantis-static@0.0.1654736714924/libs/izitoast/dist/css/iziToast.min.css","js":"https://unpkg.com/volantis-static@0.0.1654736714924/libs/izitoast/dist/js/iziToast.min.js","icon":{"default":"fa-solid fa-info-circle light-blue","quection":"fa-solid fa-question-circle light-blue"},"time":{"default":5000,"quection":20000},"position":"topRight","transitionIn":"bounceInLeft","transitionOut":"fadeOutRight","titleColor":"var(--color-text)","messageColor":"var(--color-text)","backgroundColor":"var(--color-card)","zindex":2147483647,"copyright":{"enable":true,"title":"知识共享许可协议","message":"请遵守 CC BY-NC-SA 4.0 协议。","icon":"far fa-copyright light-blue"},"aplayer":{"enable":true,"play":"fa-solid fa-play","pause":"fa-solid fa-pause"},"rightmenu":{"enable":true,"notice":true}},
      fancybox: {"css":"https://unpkg.com/volantis-static@0.0.1654736714924/libs/@fancyapps/ui/dist/fancybox.css","js":"https://unpkg.com/volantis-static@0.0.1654736714924/libs/@fancyapps/ui/dist/fancybox.umd.js"},
      
      
      
    }
  }

  /******************** volantis.EventListener ********************************/
  // 事件监听器 see: /source/js/app.js
  volantis.EventListener = {}
  // 这里存放pjax切换页面时将被移除的事件监听器
  volantis.EventListener.list = []
  //构造方法
  function volantisEventListener(type, f, ele) {
    this.type = type
    this.f = f
    this.ele = ele
  }
  // 移除事件监听器
  volantis.EventListener.remove = () => {
    volantis.EventListener.list.forEach(function (i) {
      i.ele.removeEventListener(i.type, i.f, false)
    })
    volantis.EventListener.list = []
  }
  /******************** volantis.dom.$ ********************************/
  // 注：这里没有选择器，也没有forEach一次只处理一个dom，这里重新封装主题常用的dom方法，返回的是dom对象，对象包含了以下方法，同时保留dom的原生API
  function volantisDom(ele) {
    if (!ele) ele = document.createElement("div")
    this.ele = ele;
    // ==============================================================
    this.ele.find = (c) => {
      let q = this.ele.querySelector(c)
      if (q)
        return new volantisDom(q)
    }
    // ==============================================================
    this.ele.hasClass = (c) => {
      return this.ele.className.match(new RegExp('(\\s|^)' + c + '(\\s|$)'));
    }
    this.ele.addClass = (c) => {
      this.ele.classList.add(c);
      return this.ele
    }
    this.ele.removeClass = (c) => {
      this.ele.classList.remove(c);
      return this.ele
    }
    this.ele.toggleClass = (c) => {
      if (this.ele.hasClass(c)) {
        this.ele.removeClass(c)
      } else {
        this.ele.addClass(c)
      }
      return this.ele
    }
    // ==============================================================
    // 参数 r 为 true 表示pjax切换页面时事件监听器将被移除，false不移除
    this.ele.on = (c, f, r = 1) => {
      this.ele.addEventListener(c, f, false)
      if (r) {
        volantis.EventListener.list.push(new volantisEventListener(c, f, this.ele))
      }
      return this.ele
    }
    this.ele.click = (f, r) => {
      this.ele.on("click", f, r)
      return this.ele
    }
    this.ele.scroll = (f, r) => {
      this.ele.on("scroll", f, r)
      return this.ele
    }
    // ==============================================================
    this.ele.html = (c) => {
      // if(c=== undefined){
      //   return this.ele.innerHTML
      // }else{
      this.ele.innerHTML = c
      return this.ele
      // }
    }
    // ==============================================================
    this.ele.hide = (c) => {
      this.ele.style.display = "none"
      return this.ele
    }
    this.ele.show = (c) => {
      this.ele.style.display = "block"
      return this.ele
    }
    // ==============================================================
    return this.ele
  }
  volantis.dom.$ = (ele) => {
    return !!ele ? new volantisDom(ele) : null;
  }
  /******************** RunItem ********************************/
  function RunItem() {
    this.list = []; // 存放回调函数
    this.start = () => {
      for (var i = 0; i < this.list.length; i++) {
        this.list[i].run();
      }
    };
    this.push = (fn, name, setRequestAnimationFrame = true) => {
      let myfn = fn
      if (setRequestAnimationFrame) {
        myfn = ()=>{
          volantis.requestAnimationFrame(fn)
        }
      }
      var f = new Item(myfn, name);
      this.list.push(f);
    };
    this.remove = (name) =>{
      for (let index = 0; index < this.list.length; index++) {
        const e = this.list[index];
        if (e.name == name) {
          this.list.splice(index,1);
        }
      }
    }
    // 构造一个可以run的对象
    function Item(fn, name) {
      // 函数名称
      this.name = name || fn.name;
      // run方法
      this.run = () => {
        try {
          fn()
        } catch (error) {
          console.log(error);
        }
      };
    }
  }
  /******************** Pjax ********************************/
  // /layout/_plugins/pjax/index.ejs
  // volantis.pjax.send(callBack[,"callBackName"]) 传入pjax:send回调函数
  // volantis.pjax.push(callBack[,"callBackName"]) 传入pjax:complete回调函数
  // volantis.pjax.error(callBack[,"callBackName"]) 传入pjax:error回调函数
  volantis.pjax = {};
  volantis.pjax.method = {
    complete: new RunItem(),
    error: new RunItem(),
    send: new RunItem(),
  };
  volantis.pjax = Object.assign(volantis.pjax, {
    push: volantis.pjax.method.complete.push,
    error: volantis.pjax.method.error.push,
    send: volantis.pjax.method.send.push,
  });
  /******************** RightMenu ********************************/
  // volantis.rightmenu.handle(callBack[,"callBackName"]) 外部菜单项控制
  // 可在 volantis.mouseEvent 处获取右键事件
  volantis.rightmenu = {};
  volantis.rightmenu.method = {
    handle: new RunItem(),
  }
  volantis.rightmenu = Object.assign(volantis.rightmenu, {
    handle: volantis.rightmenu.method.handle.push,
  });
  /********************  Dark Mode  ********************************/
  // /layout/_partial/scripts/darkmode.ejs
  // volantis.dark.mode 当前模式 dark or light
  // volantis.dark.toggle() 暗黑模式触发器
  // volantis.dark.push(callBack[,"callBackName"]) 传入触发器回调函数
  volantis.dark = {};
  volantis.dark.method = {
    toggle: new RunItem(),
  };
  volantis.dark = Object.assign(volantis.dark, {
    push: volantis.dark.method.toggle.push,
  });
  /********************  Message  ********************************/
  // VolantisApp.message
  /********************  isMobile  ********************************/
  // /source/js/app.js
  // volantis.isMobile
  // volantis.isMobileOld
  /********************脚本动态加载函数********************************/
  // volantis.js(src, cb)  cb 可以传入onload回调函数 或者 JSON对象 例如: volantis.js("src", ()=>{}) 或 volantis.js("src", {defer:true,onload:()=>{}})
  // volantis.css(src)

  // 返回Promise对象，如下方法同步加载资源，这利于处理文件资源之间的依赖关系，例如：APlayer 需要在 MetingJS 之前加载
  // (async () => {
  //     await volantis.js("...theme.plugins.aplayer.js.aplayer...")
  //     await volantis.js("...theme.plugins.aplayer.js.meting...")
  // })();

  // 已经加入了setTimeout
  volantis.js = (src, cb) => {
    return new Promise(resolve => {
      setTimeout(function () {
        var HEAD = document.getElementsByTagName("head")[0] || document.documentElement;
        var script = document.createElement("script");
        script.setAttribute("type", "text/javascript");
        if (cb) {
          if (JSON.stringify(cb)) {
            for (let p in cb) {
              if (p == "onload") {
                script[p] = () => {
                  cb[p]()
                  resolve()
                }
              } else {
                script[p] = cb[p]
                script.onload = resolve
              }
            }
          } else {
            script.onload = () => {
              cb()
              resolve()
            };
          }
        } else {
          script.onload = resolve
        }
        script.setAttribute("src", src);
        HEAD.appendChild(script);
      });
    });
  }
  volantis.css = (src) => {
    return new Promise(resolve => {
      setTimeout(function () {
        var link = document.createElement('link');
        link.rel = "stylesheet";
        link.href = src;
        link.onload = resolve;
        document.getElementsByTagName("head")[0].appendChild(link);
      });
    });
  }
  /********************按需加载的插件********************************/
  // volantis.import.jQuery().then(()=>{})
  volantis.import = {
    jQuery: () => {
      if (typeof jQuery == "undefined") {
        return volantis.js("https://unpkg.com/volantis-static@0.0.1654736714924/libs/jquery/dist/jquery.min.js")
      } else {
        return new Promise(resolve => {
          resolve()
        });
      }
    }
  }
  /********************** requestAnimationFrame ********************************/
  // 1、requestAnimationFrame 会把每一帧中的所有 DOM 操作集中起来，在一次重绘或回流中就完成，并且重绘或回流的时间间隔紧紧跟随浏览器的刷新频率，一般来说，这个频率为每秒60帧。
  // 2、在隐藏或不可见的元素中，requestAnimationFrame 将不会进行重绘或回流，这当然就意味着更少的的 cpu，gpu 和内存使用量。
  volantis.requestAnimationFrame = (fn)=>{
    if (!window.requestAnimationFrame) {
      window.requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame;
    }
    window.requestAnimationFrame(fn)
  }
  /************************ layoutHelper *****************************************/
  volantis.layoutHelper = (helper, html, opt)=>{
    opt = Object.assign({clean:false, pjax:true}, opt)
    function myhelper(helper, html, clean) {
      volantis.tempDiv = document.createElement("div");
      volantis.tempDiv.innerHTML = html;
      let layoutHelper = document.querySelector("#layoutHelper-"+helper)
      if (layoutHelper) {
        if (clean) {
          layoutHelper.innerHTML = ""
        }
        layoutHelper.append(volantis.tempDiv);
      }
    }
    myhelper(helper, html, opt.clean)
    if (opt.pjax) {
      volantis.pjax.push(()=>{
        myhelper(helper, html, opt.clean)
      },"layoutHelper-"+helper)
    }
  }
  /****************************** 滚动事件处理 ****************************************/
  volantis.scroll = {
    engine: new RunItem(),
    unengine: new RunItem(),
  };
  volantis.scroll = Object.assign(volantis.scroll, {
    push: volantis.scroll.engine.push,
  });
  // 滚动条距离顶部的距离
  volantis.scroll.getScrollTop = () =>{
    let scrollPos;
    if (window.pageYOffset) {
      scrollPos = window.pageYOffset;
    } else if (document.compatMode && document.compatMode != 'BackCompat') {
      scrollPos = document.documentElement.scrollTop;
    } else if (document.body) {
      scrollPos = document.body.scrollTop;
    }
    return scrollPos;
  }
  // 使用 requestAnimationFrame 处理滚动事件
  // `volantis.scroll.del` 中存储了一个数值, 该数值检测一定时间间隔内滚动条滚动的位移, 数值的检测频率是浏览器的刷新频率. 数值为正数时, 表示向下滚动. 数值为负数时, 表示向上滚动.
  volantis.scroll.handleScrollEvents = () => {
    volantis.scroll.lastScrollTop = volantis.scroll.getScrollTop()
    function loop() {
      const scrollTop = volantis.scroll.getScrollTop();
      if (volantis.scroll.lastScrollTop !== scrollTop) {
        volantis.scroll.del = scrollTop - volantis.scroll.lastScrollTop;
        volantis.scroll.lastScrollTop = scrollTop;
        // if (volantis.scroll.del > 0) {
        //   console.log("向下滚动");
        // } else {
        //   console.log("向上滚动");
        // }
        // 注销过期的unengine未滚动事件
        volantis.scroll.unengine.list=[]
        volantis.scroll.engine.start();
      }else{
        volantis.scroll.unengine.start();
      }
      volantis.requestAnimationFrame(loop)
    }
    volantis.requestAnimationFrame(loop)
  }
  volantis.scroll.handleScrollEvents()
  volantis.scroll.ele = null;
  // 触发页面滚动至目标元素位置
  volantis.scroll.to = (ele, option = {}) => {
    if (!ele) return;
    volantis.scroll.ele = ele;
    // 默认配置
    opt = {
      top: ele.getBoundingClientRect().top + document.documentElement.scrollTop,
      behavior: "smooth"
    }
    // 定义配置
    if ("top" in option) {
      opt.top = option.top
    }
    if ("behavior" in option) {
      opt.behavior = option.behavior
    }
    if ("addTop" in option) {
      opt.top += option.addTop
    }
    if (!("observerDic" in option)) {
      option.observerDic = 100
    }
    // 滚动
    window.scrollTo(opt);
    // 监视器
    // 监视并矫正元素滚动到指定位置
    // 用于处理 lazyload 引起的 cls 导致的定位失败问题
    // option.observer = false
    if (option.observer) {
      setTimeout(() => {
        if (volantis.scroll.ele != ele) {
          return
        }
        volantis.scroll.unengine.push(() => {
          let me = ele.getBoundingClientRect().top
          if(!(me >= -option.observerDic && me <= option.observerDic)){
            volantis.scroll.to(ele, option)
          }
          volantis.scroll.unengine.remove("unengineObserver")
        },"unengineObserver")
      },1000)
    }
  }
  /********************** Content Visibility ********************************/
  // 见 source/css/first.styl 如果遇到任何问题 删除 .post-story 即可
  // 一个元素被声明 content-visibility 属性后 如果元素不在 viewport 中 浏览器不会计算其后代元素样式和属性 从而节省 Style & Layout 耗时
  // content-visibility 的副作用: 锚点失效 等等(实验初期 暂不明确), 使用此方法清除样式
  volantis.cleanContentVisibility = ()=>{
    if (document.querySelector(".post-story")) {
      console.log("cleanContentVisibility");
      document.querySelectorAll(".post-story").forEach(e=>{
        e.classList.remove("post-story")
      })
    }
  }
  /******************************************************************************/
  /******************************************************************************/
  /******************************************************************************/
  //图像加载出错时的处理
  function errorImgAvatar(img) {
    img.src = "https://unpkg.com/volantis-static@0.0.1654736714924/media/placeholder/avatar/round/3442075.svg";
    img.onerror = null;
  }
  function errorImgCover(img) {
    img.src = "https://unpkg.com/volantis-static@0.0.1654736714924/media/placeholder/cover/76b86c0226ffd.svg";
    img.onerror = null;
  }
  /******************************************************************************/
</script>

  <!-- import head_end begin -->
  <!-- import head_end end -->
  <!-- Custom Files headEnd begin-->
  
  <!-- Custom Files headEnd end-->
  <!-- front-matter head_end begin -->
  <!-- front-matter head_end end -->
</head>
  <body itemscope itemtype="http://schema.org/WebPage">
    <!-- import body_begin begin-->
    <!-- import body_begin end-->
    <!-- Custom Files bodyBegin begin-->
    
    <!-- Custom Files bodyBegin end-->
    <!-- front-matter body_begin begin -->
    <!-- front-matter body_begin end -->
    <header itemscope itemtype="http://schema.org/WPHeader" id="l_header" class="l_header auto shadow floatable blur show" style='opacity: 0' >
  <div class='container'>
  <div id='wrapper'>
    <div class='nav-sub'>
      <p class="title"></p>
      <ul class='switcher nav-list-h m-phone' id="pjax-header-nav-list">
        <li><a id="s-comment" class="fa-solid fa-comments fa-fw" target="_self"  href="/" onclick="return false;" title="comment"></a></li>
        
          <li><a id="s-toc" class="s-toc fa-solid fa-list fa-fw" target="_self"  href="/" onclick="return false;" title="toc"></a></li>
        
      </ul>
    </div>
		<div class="nav-main">
      
        
        <a class="title flat-box" target="_self" href='/'>
          
            <img no-lazy class='logo' src='https://unpkg.com/volantis-static@0.0.1654736714924/media/org.volantis/blog/Logo-NavBar@3x.png'/>
          
          
          
        </a>
      

			<div class='menu navigation'>
				<ul class='nav-list-h m-pc'>
          
          
          
            
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover"
                href="/" title="博客"
                  
                  
                  
                    active-action="action-home"
                  >
                  <i class='fa-solid fa-rss fa-fw'></i>博客
                </a>
                
              </li>
            
          
          
            
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover"
                href="/categories/" title="分类"
                  
                  
                  
                    active-action="action-categories"
                  >
                  <i class='fa-solid fa-folder-open fa-fw'></i>分类
                </a>
                
              </li>
            
          
          
            
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover"
                href="/tags/" title="标签"
                  
                  
                  
                    active-action="action-tags"
                  >
                  <i class='fa-solid fa-tags fa-fw'></i>标签
                </a>
                
              </li>
            
          
          
            
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover"
                href="/archives/" title="归档"
                  
                  
                  
                    active-action="action-archives"
                  >
                  <i class='fa-solid fa-archive fa-fw'></i>归档
                </a>
                
              </li>
            
          
          
            
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover"
                href="/friends/" title="友链"
                  
                  
                  
                    active-action="action-friends"
                  >
                  <i class='fa-solid fa-link fa-fw'></i>友链
                </a>
                
              </li>
            
          
          
            
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover"
                href="/about/" title="关于"
                  
                  
                  
                    active-action="action-about"
                  >
                  <i class='fa-solid fa-info-circle fa-fw'></i>关于
                </a>
                
              </li>
            
          
          
				</ul>
			</div>
      
      <div class="m_search">
        <form name="searchform" class="form u-search-form">
          <i class="icon fa-solid fa-search fa-fw"></i>
          <input type="text" class="input u-search-input" placeholder="Search..." />
        </form>
      </div>
      

			<ul class='switcher nav-list-h m-phone'>
				
					<li><a class="s-search fa-solid fa-search fa-fw" target="_self" href="/" onclick="return false;" title="search"></a></li>
				
				<li>
          <a class="s-menu fa-solid fa-bars fa-fw" target="_self" href="/" onclick="return false;" title="menu"></a>
          <ul class="menu-phone list-v navigation white-box">
            
              
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover"
                href="/" title="博客"
                  
                  
                  
                    active-action="action-home"
                  >
                  <i class='fa-solid fa-rss fa-fw'></i>博客
                </a>
                
              </li>
            
          
            
              
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover"
                href="/categories/" title="分类"
                  
                  
                  
                    active-action="action-categories"
                  >
                  <i class='fa-solid fa-folder-open fa-fw'></i>分类
                </a>
                
              </li>
            
          
            
              
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover"
                href="/tags/" title="标签"
                  
                  
                  
                    active-action="action-tags"
                  >
                  <i class='fa-solid fa-tags fa-fw'></i>标签
                </a>
                
              </li>
            
          
            
              
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover"
                href="/archives/" title="归档"
                  
                  
                  
                    active-action="action-archives"
                  >
                  <i class='fa-solid fa-archive fa-fw'></i>归档
                </a>
                
              </li>
            
          
            
              
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover"
                href="/friends/" title="友链"
                  
                  
                  
                    active-action="action-friends"
                  >
                  <i class='fa-solid fa-link fa-fw'></i>友链
                </a>
                
              </li>
            
          
            
              
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover"
                href="/about/" title="关于"
                  
                  
                  
                    active-action="action-about"
                  >
                  <i class='fa-solid fa-info-circle fa-fw'></i>关于
                </a>
                
              </li>
            
          
            
          </ul>
        </li>
			</ul>

      <!-- Custom Files header begin -->
      
      <!-- Custom Files header end -->
		</div>
	</div>
  </div>
</header>

    <div id="l_body">
      <div id="l_cover">
  
    
      <!-- see: /layout/_partial/scripts/_ctrl/coverCtrl.ejs -->
      <div id="none" class='cover-wrapper post dock' style="display: none;">
        
  <div class='cover-bg lazyload placeholder' data-bg="https://gcore.jsdelivr.net/gh/MHG-LAB/cron@gh-pages/bing/bing.jpg"></div>

<div class='cover-body'>
  <div class='top'>
    
    
      <p class="title">Volantis</p>
    
    
  </div>
  <div class='bottom'>
    <div class='menu navigation'>
      <div class='list-h'>
        
          
            <a href="/v4/getting-started/"
              
              
              active-action="action-v4getting-started">
              <img src='https://unpkg.com/volantis-static@0.0.1654736714924/media/twemoji/assets/svg/1f5c3.svg'><p>文档</p>
            </a>
          
            <a href="/faqs/"
              
              
              active-action="action-faqs">
              <img src='https://unpkg.com/volantis-static@0.0.1654736714924/media/twemoji/assets/svg/1f516.svg'><p>帮助</p>
            </a>
          
            <a href="/examples/"
              
              
              active-action="action-examples">
              <img src='https://unpkg.com/volantis-static@0.0.1654736714924/media/twemoji/assets/svg/1f396.svg'><p>示例</p>
            </a>
          
            <a href="/contributors/"
              
              
              active-action="action-contributors">
              <img src='https://unpkg.com/volantis-static@0.0.1654736714924/media/twemoji/assets/svg/1f389.svg'><p>社区</p>
            </a>
          
            <a href="/archives/"
              
              
              active-action="action-archives">
              <img src='https://unpkg.com/volantis-static@0.0.1654736714924/media/twemoji/assets/svg/1f4f0.svg'><p>博客</p>
            </a>
          
            <a target="_blank" rel="noopener" href="https://github.com/volantis-x/hexo-theme-volantis/"
              
              
              active-action="action-https:githubcomvolantis-xhexo-theme-volantis">
              <img src='https://unpkg.com/volantis-static@0.0.1654736714924/media/twemoji/assets/svg/1f9ec.svg'><p>源码</p>
            </a>
          
        
      </div>
    </div>
  </div>
</div>

        <div id="scroll-down" style="display: none;"><i class="fa fa-chevron-down scroll-down-effects"></i></div>
      </div>
    
  
</div>

      <div id="safearea">
        <div class="body-wrapper">
          
<div id="l_main" class=''>
  <article itemscope itemtype="http://schema.org/Article" class="article post white-box reveal md shadow floatable blur article-type-post" id="post" itemscope itemprop="blogPost">
  <link itemprop="mainEntityOfPage" href="http://8.219.11.28/2024/02/23/前后端-Spring框架课堂笔记/">
  <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
    <meta itemprop="name" content="欢迎来到我的个人博客~">
  </span>
  <span hidden itemprop="post" itemscope itemtype="http://schema.org/Post">
    <meta itemprop="name" content="欢迎来到我的个人博客~">
    <meta itemprop="description" content="这些技术大部分是自己总结的，非官方">
  </span>
  


  
    <span hidden>
      <meta itemprop="image" content="https://unpkg.com/volantis-static@0.0.1654736714924/media/org.volantis/blog/favicon/android-chrome-192x192.png">
    </span>
  
  <div class="article-meta" id="top">
    
    
    
      <span hidden itemprop="name headline">
        
      </span>
    
  </div>


  <div id="layoutHelper-page-plugins"></div>
  <div id="post-body" itemprop="articleBody">
    <h1 id="Spring框架课堂笔记"><a href="#Spring框架课堂笔记" class="headerlink" title="Spring框架课堂笔记"></a>Spring框架课堂笔记</h1><p><strong>Spring概述，ioC ， DI ，AOP ，整合JDBC ，事务管理</strong></p>
<h1 id="1-Spring概述"><a href="#1-Spring概述" class="headerlink" title="1. Spring概述"></a>1. Spring概述</h1><h2 id="1-1-什么是框架？"><a href="#1-1-什么是框架？" class="headerlink" title="1.1 什么是框架？"></a>1.1 什么是框架？</h2><p>框架（Framework）：框（指其约束性）架（指其支撑性），在软件设计中指为解决一个开放性问题而设计的具有一定约束性的支撑结构。在此结构上可以根据具体问题扩展、安插更多的组成部分，从而更迅速和方便地构建完整的解决问题的方案。</p>
<blockquote>
<p>1、框架本身一般不完整到可以解决特定问题</p>
<p>2、框架天生就是为扩展而设计的</p>
<p>3、框架里面可以为后续扩展的组件提供很多辅助性、支撑性的方便易用的实用工具（utilities），也就是说框架时常配套了一些帮助解决某类问题的库（libraries）或工具（tools）。</p>
</blockquote>
<p>如何学习框架呢？</p>
<p>1、知道框架能做什么</p>
<p>2、学习框架的语法，一般框架完成一个功能需要一定的步骤</p>
<p>3、框架的内部实现原理（扩展）</p>
<p>4、尝试实现一个框架（提升）</p>
<h2 id="1-2-Spring是什么"><a href="#1-2-Spring是什么" class="headerlink" title="1.2 Spring是什么"></a>1.2 Spring是什么</h2><p>Spring官网 <a target="_blank" rel="noopener" href="https://spring.io/">https://spring.io</a></p>
<p>Spring 被称为 J2EE 的春天，是一个是分层的 Java SE&#x2F;EE <strong>full-stack</strong> <strong>开源</strong>的<strong>轻量级</strong>的 Java 开发框架， 是最受欢迎的企业级 Java 应用程序开发框架，数以百万的来自世界各地的开发人员使用 Spring 框架来创建性能好、易于测试、可重用的代码。</p>
<p>Spring具有<strong>控制反转</strong>（IoC）和<strong>面向切面</strong>（AOP）两大核心。Java Spring 框架通过声明式方式灵活地进行<strong>事务的管理</strong>，提高开发效率和质量。</p>
<p>Spring 框架不仅限于服务器端的开发。从简单性、可测试性和松耦合的角度而言，任何 Java 应用都可以从 Spring 中受益。Spring 框架还是一个超级粘合平台，除了自己提供功能外，还提供粘合其他技术和框架的能力。</p>
<h2 id="1-3-Spring的优势"><a href="#1-3-Spring的优势" class="headerlink" title="1.3 Spring的优势"></a>1.3 Spring的优势</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">1、方便解耦，简化开发</span><br><span class="line">	Spring 就是一个大工厂，可以将所有对象的创建和依赖关系的维护交给 Spring 管理。</span><br><span class="line"></span><br><span class="line">2、方便集成各种优秀框架</span><br><span class="line">	Spring 不排斥各种优秀的开源框架，其内部提供了对各种优秀框架（如 Struts2、Hibernate、MyBatis 等）的直接支持。</span><br><span class="line"></span><br><span class="line">3、降低 Java EE API 的使用难度</span><br><span class="line">	Spring 对 Java EE 开发中非常难用的一些 API（JDBC、JavaMail、远程调用等）都提供了封装，使这些 API 应用的难度大大降低。</span><br><span class="line"></span><br><span class="line">4、方便程序的测试</span><br><span class="line">	Spring 支持 JUnit4，可以通过注解方便地测试 Spring 程序。</span><br><span class="line"></span><br><span class="line">5、AOP 编程的支持</span><br><span class="line">	Spring 提供面向切面编程，可以方便地实现对程序进行权限拦截和运行监控等功能。</span><br><span class="line"></span><br><span class="line">6、声明式事务的支持</span><br><span class="line">	只需要通过配置就可以完成对事务的管理，而无须手动编程。</span><br></pre></td></tr></table></figure>

<h2 id="1-4-Spring的体系结构"><a href="#1-4-Spring的体系结构" class="headerlink" title="1.4 Spring的体系结构"></a>1.4 Spring的体系结构</h2><p>Spring 为我们提供了一站式解决方案，但Spring 是模块化的，允许咱们挑选和选择适用于项目的模块，不需要把剩余部分也引入。</p>
<p>Spring 框架提供约 20 个模块，可以根据应用程序的要求来选择。</p>
<p><img src="F:\JAVA笔记库\img\image-20210315120423534.png" class="lazyload" data-srcset="F:\JAVA笔记库\img\image-20210315120423534.png" srcset="" alt="image-20210315120423534"></p>
<h3 id="1-4-1-核心容器"><a href="#1-4-1-核心容器" class="headerlink" title="1.4.1 核心容器"></a>1.4.1 核心容器</h3><p>核心容器由 <strong>Spring-core，Spring-beans，Spring-context，Spring-context-support和Spring-expression</strong>（SpEL，Spring 表达式语言，Spring Expression Language）等模块组成</p>
<ul>
<li><strong>Spring-core</strong> 模块提供了框架的基本组成部分，包括 IoC 和依赖注入功能。</li>
<li><strong>Spring-beans</strong> 模块提供 BeanFactory，工厂模式的微妙实现，它移除了编码式单例的需要，并且可以把配置和依赖从实际编码逻辑中解耦。</li>
<li><strong>context</strong> 模块建立在由 <strong>core</strong>和 <strong>beans</strong> 模块的基础上建立起来的，它以一种类似于 JNDI 注册的方式访问对象。Context 模块继承自 Bean 模块，并且添加了国际化（比如，使用资源束）、事件传播、资源加载和透明地创建上下文（比如，通过 Servelet 容器）等功能。Context 模块也支持 Java EE 的功能，比如 EJB、JMX 和远程调用等。<strong>ApplicationContext</strong> 接口是 Context 模块的焦点。<strong>Spring-context-support</strong> 提供了对第三方集成到 Spring 上下文的支持，比如缓存（EhCache, Guava, JCache）、邮件（JavaMail）、调度（CommonJ, Quartz）、模板引擎（FreeMarker, JasperReports, Velocity）等。</li>
<li><strong>Spring-expression</strong> 模块提供了强大的表达式语言，用于在运行时查询和操作对象图。它是 JSP2.1 规范中定义的统一表达式语言的扩展，支持 set 和 get 属性值、属性赋值、方法调用、访问数组集合及索引的内容、逻辑算术运算、命名变量、通过名字从 Spring IoC 容器检索对象，还支持列表的投影、选择以及聚合等。</li>
</ul>
<p>它们的完整依赖关系如下图所示：</p>
<p><img src="https://atts.w3cschool.cn/attachments/image/20181023/1540290875453691.png" class="lazyload" data-srcset="https://atts.w3cschool.cn/attachments/image/20181023/1540290875453691.png" srcset="" alt="Spring 体系结构"></p>
<h3 id="1-4-2-数据访问-集成"><a href="#1-4-2-数据访问-集成" class="headerlink" title="1.4.2 数据访问&#x2F;集成"></a>1.4.2 数据访问&#x2F;集成</h3><p>JDBC&#x3D;Java Data Base Connectivity，ORM&#x3D;Object Relational Mapping，OXM&#x3D;Object XML Mapping，JMS&#x3D;Java Message Service</p>
<ul>
<li><strong>JDBC</strong> 模块提供了 JDBC 抽象层，它消除了冗长的 JDBC 编码和对数据库供应商特定错误代码的解析。</li>
<li><strong>ORM</strong> 模块提供了对流行的对象关系映射 API 的集成，包括 JPA、JDO 和 Hibernate 等。通过此模块可以让这些 ORM 框架和 Spring的其它功能整合，比如前面提及的事务管理。</li>
<li><strong>OXM</strong> 模块提供了对 OXM 实现的支持，比如 JAXB、Castor、XML Beans、JiBX、XStream 等。</li>
<li><strong>JMS</strong> 模块包含生产（produce）和消费（consume）消息的功能。从 Spring 4.1 开始，集成了 Spring-messaging 模块。</li>
<li><strong>事务</strong>模块为实现特殊接口类及所有的 POJO 支持编程式和声明式事务管理。</li>
</ul>
<h3 id="1-4-3-Web"><a href="#1-4-3-Web" class="headerlink" title="1.4.3 Web"></a>1.4.3 Web</h3><ul>
<li><strong>Web</strong> 模块提供面向 web 的基本功能和面向 web 的应用上下文，比如多部分（multipart）文件上传功能、使用 Servlet 监听器初始化 IoC 容器等。它还包括 HTTP 客户端以及 Spring 远程调用中与 web 相关的部分。</li>
<li><strong>Web-MVC</strong> 模块为 web 应用提供了模型视图控制（MVC）和 REST Web服务的实现。Spring 的 MVC 框架可以使领域模型代码和 web 表单完全地分离，且可以与 Spring 框架的其它所有功能进行集成。</li>
<li><strong>Web-Socket</strong> 模块为 WebSocket-based 提供了支持，而且在 web 应用程序中提供了客户端和服务器端之间通信的两种方式。</li>
<li><strong>Web-Portlet</strong> 模块提供了用于 Portlet 环境的 MVC 实现，并反映了 Spring-webmvc 模块的功能。</li>
</ul>
<h3 id="1-4-4-其他"><a href="#1-4-4-其他" class="headerlink" title="1.4.4 其他"></a>1.4.4 其他</h3><ul>
<li><strong>AOP</strong> 模块提供了面向方面（切面）的编程实现，允许你定义方法拦截器和切入点对代码进行干净地解耦，从而使实现功能的代码彻底的解耦出来。</li>
<li><strong>Aspects</strong> 模块提供了与 <strong>AspectJ</strong> 的集成，这是一个功能强大且成熟的面向切面编程（AOP）框架。</li>
<li><strong>Instrumentation</strong> 模块在一定的应用服务器中提供了类 instrumentation 的支持和类加载器的实现。</li>
<li><strong>Messaging</strong> 模块为 STOMP 提供了支持作为在应用程序中 WebSocket 子协议的使用。它也支持一个注解编程模型，它是为了选路和处理来自 WebSocket 客户端的 STOMP 信息。</li>
<li><strong>测试</strong>模块支持对具有 JUnit 或 TestNG 框架的 Spring 组件的测试。</li>
</ul>
<h1 id="2、Spring核心之IoC控制反转"><a href="#2、Spring核心之IoC控制反转" class="headerlink" title="2、Spring核心之IoC控制反转"></a>2、Spring核心之IoC控制反转</h1><h2 id="2-1-IoC的概念"><a href="#2-1-IoC的概念" class="headerlink" title="2.1 IoC的概念"></a>2.1 IoC的概念</h2><p>Ioc—Inversion of Control，即“控制反转”，不是什么技术，而是一种设计思想。</p>
<p>IoC 是指在程序开发中，实例的创建不再由调用者管理，而是由 Spring 容器创建。Spring 容器会负责控制程序之间的关系，而不是由程序代码直接控制，因此，控制权由程序代码转移到了 Spring 容器中，控制权发生了反转，这就是 Spring 的 IoC 思想。</p>
<p>创建实例：new  反射  克隆  序列化   动态代理</p>
<p>例如在Servlet应用中 我们没有创建Servlet对象，而是通过ServletContext容器来创建的 spring也是一样的道理</p>
<h2 id="2-2-Spring入门案例"><a href="#2-2-Spring入门案例" class="headerlink" title="2.2 Spring入门案例"></a>2.2 Spring入门案例</h2><h3 id="2-2-1-创建maven项目"><a href="#2-2-1-创建maven项目" class="headerlink" title="2.2.1 创建maven项目"></a>2.2.1 创建maven项目</h3><p>创建完毕的目录结构</p>
<p><img src="/img%5Cimage-20210315131440682.png" class="lazyload" data-srcset="/img%5Cimage-20210315131440682.png" srcset="" alt="image-20210315131440682"></p>
<h3 id="2-2-2-pom-xml文件添加依赖和插件"><a href="#2-2-2-pom-xml文件添加依赖和插件" class="headerlink" title="2.2.2 pom.xml文件添加依赖和插件"></a>2.2.2 pom.xml文件添加依赖和插件</h3><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependencies</span>&gt;</span></span><br><span class="line">        <span class="comment">&lt;!--单元测试--&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>junit<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>junit<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">version</span>&gt;</span>4.12<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">scope</span>&gt;</span>test<span class="tag">&lt;/<span class="name">scope</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line">    	<span class="comment">&lt;!--spring依赖--&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-context<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">version</span>&gt;</span>5.2.13.RELEASE<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">dependencies</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">build</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">plugins</span>&gt;</span></span><br><span class="line">            <span class="comment">&lt;!--编译插件--&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">plugin</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.apache.maven.plugins<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>maven-compiler-plugin<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">version</span>&gt;</span>3.8.0<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">configuration</span>&gt;</span></span><br><span class="line">                    <span class="tag">&lt;<span class="name">source</span>&gt;</span>1.8<span class="tag">&lt;/<span class="name">source</span>&gt;</span></span><br><span class="line">                    <span class="tag">&lt;<span class="name">target</span>&gt;</span>1.8<span class="tag">&lt;/<span class="name">target</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;/<span class="name">configuration</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;/<span class="name">plugin</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">plugins</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">build</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p><strong>依赖关系:</strong></p>
<p>我们引入springcontext容器后，他会自动依赖四个依赖，aop,beans,core,expression</p>
<p><img src="F:\JAVA笔记库\img\111111.png" class="lazyload" data-srcset="F:\JAVA笔记库\img\111111.png" srcset=""></p>
<h3 id="2-2-3-创建一个实体类"><a href="#2-2-3-创建一个实体类" class="headerlink" title="2.2.3 创建一个实体类"></a>2.2.3 创建一个实体类</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.lina.pojo;</span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 实体类球队</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Team</span> &#123;</span><br><span class="line">    <span class="keyword">private</span> Integer id;</span><br><span class="line">    <span class="keyword">private</span> String name;</span><br><span class="line">    <span class="keyword">private</span> String location;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">Team</span><span class="params">()</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;Team的默认构造方法被调用：id=&quot;</span>+id+<span class="string">&quot;,name=&quot;</span>+name+<span class="string">&quot;, location=&quot;</span>+location);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="2-3-4-创建Spring的配置文件application-xml"><a href="#2-3-4-创建Spring的配置文件application-xml" class="headerlink" title="2.3.4 创建Spring的配置文件application.xml"></a>2.3.4 创建Spring的配置文件application.xml</h3><p><img src="/img%5Cimage-20210315142605800.png" class="lazyload" data-srcset="/img%5Cimage-20210315142605800.png" srcset="" alt="image-20210315142605800"></p>
<h3 id="2-3-5-使用Spring容器创建对象"><a href="#2-3-5-使用Spring容器创建对象" class="headerlink" title="2.3.5 使用Spring容器创建对象"></a>2.3.5 使用Spring容器创建对象</h3><p>配置文件中创建对象</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?xml version=<span class="string">&quot;1.0&quot;</span> encoding=<span class="string">&quot;UTF-8&quot;</span>?&gt;</span></span><br><span class="line"><span class="comment">&lt;!--spring的配置文件</span></span><br><span class="line"><span class="comment">    1、beans: 根标签，spring中java的对象成为bean</span></span><br><span class="line"><span class="comment">    2、spring-beans.xsd 是约束文件（约束XML文件中能编写哪些标签）--&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">beans</span> <span class="attr">xmlns</span>=<span class="string">&quot;http://www.springframework.org/schema/beans&quot;</span></span></span><br><span class="line"><span class="tag">       <span class="attr">xmlns:xsi</span>=<span class="string">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span></span></span><br><span class="line"><span class="tag">       <span class="attr">xsi:schemaLocation</span>=<span class="string">&quot;http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd&quot;</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">&lt;!--创建对象：声明bean,通知spring要创建哪个类的对象</span></span><br><span class="line"><span class="comment">        一个bean标签声明一个对象：</span></span><br><span class="line"><span class="comment">            id=&quot;自定义的对象名称&quot; ,要求唯一</span></span><br><span class="line"><span class="comment">            class=&quot;类的完全限定名&quot; 包名+类名，spring底层是反射机制创建对象，所以必须使用类名</span></span><br><span class="line"><span class="comment">            相当于 Team team1=new Team();创建好的对象放入一个集合Map中</span></span><br><span class="line"><span class="comment">            例如：springMap.put(&quot;team1&quot;,new Team());</span></span><br><span class="line"><span class="comment">    --&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;team1&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.lina.pojo.Team&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">beans</span>&gt;</span></span><br></pre></td></tr></table></figure>

<h3 id="2-3-6-获取Spring容器"><a href="#2-3-6-获取Spring容器" class="headerlink" title="2.3.6 获取Spring容器"></a>2.3.6 获取Spring容器</h3><p>Spring 提供了两种 IoC 容器，分别为 BeanFactory 和 ApplicationContext.</p>
<h4 id="2-3-6-1-BeanFactory"><a href="#2-3-6-1-BeanFactory" class="headerlink" title="2.3.6.1 BeanFactory"></a>2.3.6.1 BeanFactory</h4><p>BeanFactory 是基础类型的 IoC 容器,是一个管理 Bean 的工厂，它主要负责初始化各种 Bean，并调用它们的生命周期方法。</p>
<p>BeanFactory 接口有多个实现类，最常见的是 org.Springframework.beans.factory.xml.XmlBeanFactory，它是根据 XML 配置文件中的定义装配 Bean 的。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">BeanFactory</span> <span class="variable">beanFactory</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">XmlBeanFactory</span>(<span class="keyword">new</span> <span class="title class_">FileSystemResource</span>(Spring配置文件的名称));</span><br></pre></td></tr></table></figure>





<h4 id="2-3-6-2-ApplicationContext"><a href="#2-3-6-2-ApplicationContext" class="headerlink" title="2.3.6.2 ApplicationContext"></a>2.3.6.2 ApplicationContext</h4><p>ApplicationContext 是 BeanFactory 的<strong>子接口</strong>，也被称为<strong>应用上下文</strong>。它不仅<strong>提供了 BeanFactory 的所有功能</strong>，还<strong>添加了对 i18n（国际化</strong>）、资源访问、事件传播等方面的良好支持。</p>
<p>ApplicationContext 接口有两个常用的实现类:</p>
<h5 id="2-6-2-2-1-ClassPathXmlApplicationContext——常用"><a href="#2-6-2-2-1-ClassPathXmlApplicationContext——常用" class="headerlink" title="2.6.2.2.1 ClassPathXmlApplicationContext——常用"></a>2.6.2.2.1 ClassPathXmlApplicationContext——常用</h5><p>该类从类路径 <strong>ClassPath</strong> 中寻找指定的 XML 配置文件，找到并装载完成 ApplicationContext 的实例化工作</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ApplicationContext applicationContext=<span class="keyword">new</span> <span class="title class_">ClassPathXmlApplicationContext</span>(Spring配置文件的名称); </span><br></pre></td></tr></table></figure>

<p><strong>这时候会发现对象被创建了 并且默认的构造被调用了</strong></p>
<p><img src="F:\JAVA笔记库\img\1010.png" class="lazyload" data-srcset="F:\JAVA笔记库\img\1010.png" srcset=""></p>
<h5 id="2-6-2-2-2-FileSystemXmlApplicationContext"><a href="#2-6-2-2-2-FileSystemXmlApplicationContext" class="headerlink" title="2.6.2.2.2 FileSystemXmlApplicationContext"></a>2.6.2.2.2 FileSystemXmlApplicationContext</h5><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ApplicationContext applicationContext = new FileSystemXmlApplicationContext(String configLocation);</span><br></pre></td></tr></table></figure>

<p>它与 ClassPathXmlApplicationContext 的区别是：在读取 Spring 的配置文件时，FileSystemXmlApplicationContext 不再从类路径中读取配置文件，而是通过参数指定配置文件的位置，它可以获取类路径之外的资源，如“D:\application.xml”。</p>
<h3 id="2-3-7-通过上下文对象获取容器中的对象"><a href="#2-3-7-通过上下文对象获取容器中的对象" class="headerlink" title="2.3.7 通过上下文对象获取容器中的对象"></a>2.3.7 通过上下文对象获取容器中的对象</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.lina.test;</span><br><span class="line"><span class="keyword">import</span> com.lina.pojo.Team;</span><br><span class="line"><span class="keyword">import</span> org.junit.Test;</span><br><span class="line"><span class="keyword">import</span> org.springframework.beans.factory.BeanFactory;</span><br><span class="line"><span class="keyword">import</span> org.springframework.beans.factory.xml.XmlBeanFactory;</span><br><span class="line"><span class="keyword">import</span> org.springframework.context.ApplicationContext;</span><br><span class="line"><span class="keyword">import</span> org.springframework.context.support.ClassPathXmlApplicationContext;</span><br><span class="line"><span class="keyword">import</span> org.springframework.context.support.FileSystemXmlApplicationContext;</span><br><span class="line"><span class="keyword">import</span> org.springframework.core.io.FileSystemResource;</span><br><span class="line"><span class="keyword">import</span> java.util.Date;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Test1</span> &#123;</span><br><span class="line">    <span class="meta">@Test</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">test01</span><span class="params">()</span>&#123;</span><br><span class="line">        <span class="comment">//使用spring容器创建对象</span></span><br><span class="line">        <span class="comment">//1、指定spring配置文件的名称</span></span><br><span class="line">        String springConfig=<span class="string">&quot;application.xml&quot;</span>;</span><br><span class="line">        <span class="comment">//2、创建spring容器的对象：</span></span><br><span class="line">        <span class="comment">//方式1:不推荐，了解</span></span><br><span class="line">        <span class="comment">//BeanFactory beanFactory = new XmlBeanFactory(new FileSystemResource(&quot;D:/workspaces/ideaProjects/MySpring/spring01/src/main/resources/application.xml&quot;));</span></span><br><span class="line">        <span class="comment">//beanFactory.getBean(&quot;team1&quot;);//根据ID从IOC容器获取对象</span></span><br><span class="line">        <span class="comment">//方式2：applicationContext--常用</span></span><br><span class="line">        ApplicationContext applicationContext=<span class="keyword">new</span> <span class="title class_">ClassPathXmlApplicationContext</span>(springConfig);<span class="comment">//这里执行完毕容器中的对象都已经创建完成</span></span><br><span class="line">        <span class="comment">//方式3：applicationContext--了解</span></span><br><span class="line">        <span class="comment">//ApplicationContext applicationContext2 = new FileSystemXmlApplicationContext(&quot;D:/workspaces/ideaProjects/MySpring/spring01/src/main/resources/application.xml&quot;);</span></span><br><span class="line">        <span class="comment">//3、获取容器中的对象</span></span><br><span class="line">       Team team1= (Team) applicationContext.getBean(<span class="string">&quot;team1&quot;</span>);</span><br><span class="line">       <span class="comment">//4、容器其他api</span></span><br><span class="line">        <span class="type">int</span> <span class="variable">beanDefinitionCount</span> <span class="operator">=</span> applicationContext.getBeanDefinitionCount();</span><br><span class="line">        System.out.println(<span class="string">&quot;spring容器中对象的个数：&quot;</span>+beanDefinitionCount);</span><br><span class="line">        String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();</span><br><span class="line">        System.out.println(<span class="string">&quot;spring容器中所有对象的名称：&quot;</span>);</span><br><span class="line">        <span class="keyword">for</span> (String name : beanDefinitionNames) &#123;</span><br><span class="line">            System.out.println(name);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="2-3-8-创建非自定义对象"><a href="#2-3-8-创建非自定义对象" class="headerlink" title="2.3.8 创建非自定义对象"></a>2.3.8 创建非自定义对象</h3><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">pox.xml文件中补充</span><br><span class="line"><span class="comment">&lt;!--创建非自定义的对象--&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;date&quot;</span> <span class="attr">class</span>=<span class="string">&quot;java.util.Date&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br></pre></td></tr></table></figure>

<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">上面的测试方法中添加如下内容：</span><br><span class="line">  <span class="comment">//5、获取日期对象</span></span><br><span class="line">  Date date1= (Date) applicationContext.getBean(<span class="string">&quot;date1&quot;</span>);</span><br><span class="line">  System.out.println(<span class="string">&quot;日期：&quot;</span>+date1);</span><br></pre></td></tr></table></figure>



<h3 id="2-3-9-bean标签的属性"><a href="#2-3-9-bean标签的属性" class="headerlink" title="2.3.9 bean标签的属性"></a>2.3.9 bean标签的属性</h3><table>
<thead>
<tr>
<th>属性</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td>class</td>
<td>指定bean对应类的全路径</td>
</tr>
<tr>
<td>name</td>
<td>name是bean对应对象的一个标识</td>
</tr>
<tr>
<td>scope</td>
<td>执行bean对象创建模式和生命周期,scope&#x3D;”singleton”和scope&#x3D;”prototype” 单例创建的对象只有一个</td>
</tr>
<tr>
<td>id</td>
<td>id是bean对象的唯一标识,不能添加特别字符</td>
</tr>
<tr>
<td>lazy-init</td>
<td>是否延时加载 默认值:false。true 延迟加载对象,当对象被调用的时候才会加载，测试的时候，通过getbean()方法获得对象。lazy-init&#x3D;”false” 默认值，不延迟，无论对象是否被使用，都会立即创建对象,测试时只需要加载配置文件即可。注意:测试的时候只留下id,class属性</td>
</tr>
<tr>
<td>init-method</td>
<td>只需要加载配置文件即可对象初始化方法</td>
</tr>
<tr>
<td>destroy-method</td>
<td>对象销毁方法</td>
</tr>
</tbody></table>
<p>示例演示：</p>
<p>Team实体类补充如下方法：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">init</span><span class="params">()</span>&#123;</span><br><span class="line">     System.out.println(<span class="string">&quot;Team ---- init()&quot;</span>);</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">destroy</span><span class="params">()</span>&#123;</span><br><span class="line">     System.out.println(<span class="string">&quot;Team ---- destroy()&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>application.xml配置文件添加如下内容：</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!--</span></span><br><span class="line"><span class="comment">    bean标签的属性:</span></span><br><span class="line"><span class="comment">    id=&quot;自定义的对象名称&quot; ,要求唯一</span></span><br><span class="line"><span class="comment">    name=&quot;bean对于的一个标识“，一般使用id居多</span></span><br><span class="line"><span class="comment">    class=&quot;类的完全限定名&quot;</span></span><br><span class="line"><span class="comment">    scope=&quot;singleton/prototype&quot; 单例/多例</span></span><br><span class="line"><span class="comment">        singleton：默认值，单例：在容器启动的时候就已经创建了对象，而且整个容器只有为一个的一个对象</span></span><br><span class="line"><span class="comment">        prototype：多例，在使用对象的时候才创建对象，每次使用都创建新的对象</span></span><br><span class="line"><span class="comment">    lazy-init=&quot;true/false&quot; 是否延迟创建对象，只针对单例有效</span></span><br><span class="line"><span class="comment">        false:默认值，不延迟创建对象，容器加载的时候立即创建</span></span><br><span class="line"><span class="comment">        true:延迟加载，使用对象的时候才去创建对象</span></span><br><span class="line"><span class="comment">    init-method=&quot;创建对象之后执行的初始化方法&quot;</span></span><br><span class="line"><span class="comment">    destroy-method=&quot;对象销毁方法，调用容器destroy方法的时候执行&quot;</span></span><br><span class="line"><span class="comment">--&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;team2&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.lina.pojo.Team&quot;</span> <span class="attr">scope</span>=<span class="string">&quot;singleton&quot;</span> <span class="attr">lazy-init</span>=<span class="string">&quot;true&quot;</span> <span class="attr">init-method</span>=<span class="string">&quot;init&quot;</span> <span class="attr">destroy-method</span>=<span class="string">&quot;destroy&quot;</span>/&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;team3&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.lina.pojo.Team&quot;</span> <span class="attr">scope</span>=<span class="string">&quot;prototype&quot;</span> /&gt;</span></span><br></pre></td></tr></table></figure>

<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Test</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">test02</span><span class="params">()</span>&#123;</span><br><span class="line">    String springConfig=<span class="string">&quot;application.xml&quot;</span>;</span><br><span class="line">    ClassPathXmlApplicationContext applicationContext=<span class="keyword">new</span> <span class="title class_">ClassPathXmlApplicationContext</span>(springConfig);</span><br><span class="line">    <span class="type">Team</span> <span class="variable">team1</span> <span class="operator">=</span> (Team) applicationContext.getBean(<span class="string">&quot;team1&quot;</span>);</span><br><span class="line">    <span class="type">Team</span> <span class="variable">team11</span> <span class="operator">=</span> (Team) applicationContext.getBean(<span class="string">&quot;team1&quot;</span>);</span><br><span class="line">    System.out.println(team1);</span><br><span class="line">    System.out.println(team11);</span><br><span class="line">    <span class="type">Team</span> <span class="variable">team2</span> <span class="operator">=</span> (Team) applicationContext.getBean(<span class="string">&quot;team2&quot;</span>);</span><br><span class="line">    <span class="type">Team</span> <span class="variable">team22</span> <span class="operator">=</span> (Team) applicationContext.getBean(<span class="string">&quot;team2&quot;</span>);</span><br><span class="line">    System.out.println(team2);</span><br><span class="line">    System.out.println(team22);</span><br><span class="line">    applicationContext.close();<span class="comment">//关闭容器</span></span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>





<h2 id="2-3-Spring容器创建对象的方式"><a href="#2-3-Spring容器创建对象的方式" class="headerlink" title="2.3 Spring容器创建对象的方式"></a>2.3 Spring容器创建对象的方式</h2><h3 id="2-3-1-使用默认的构造方法"><a href="#2-3-1-使用默认的构造方法" class="headerlink" title="2.3.1 使用默认的构造方法"></a>2.3.1 使用默认的构造方法</h3><h3 id="2-3-2-使用带参数的构造方法"><a href="#2-3-2-使用带参数的构造方法" class="headerlink" title="2.3.2 使用带参数的构造方法"></a>2.3.2 使用带参数的构造方法</h3><h3 id="2-3-3-使用工厂类"><a href="#2-3-3-使用工厂类" class="headerlink" title="2.3.3 使用工厂类"></a>2.3.3 使用工厂类</h3><p>三种方式的案例如下：</p>
<p>Team.java类中添加带参数构造方法：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="title function_">Team</span><span class="params">(Integer id, String name, String location)</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>.id = id;</span><br><span class="line">        <span class="built_in">this</span>.name = name;</span><br><span class="line">        <span class="built_in">this</span>.location = location;</span><br><span class="line">        System.out.println(<span class="string">&quot;Team - 带参数的构造方法 id=&quot;</span>+id+<span class="string">&quot;,name=&quot;</span>+name+<span class="string">&quot;,location=&quot;</span>+location);</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>

<p>创建工厂类：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.kbb.pojo;</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">MyFactory</span> &#123;</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 实例方法</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> Team <span class="title function_">instanceFun</span><span class="params">()</span>&#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;MyFactory------instanceFun&quot;</span>);</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Team</span>(<span class="number">1003</span>,<span class="string">&quot;湖人&quot;</span>,<span class="string">&quot;洛杉矶&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 静态方法</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> Team <span class="title function_">staticFun</span><span class="params">()</span>&#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;MyFactory------staticFun&quot;</span>);</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Team</span>(<span class="number">1004</span>,<span class="string">&quot;小牛&quot;</span>,<span class="string">&quot;达拉斯&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">        <span class="type">Team</span> <span class="variable">team1</span> <span class="operator">=</span> MyFactory.staticFun();</span><br><span class="line">        MyFactory factory=<span class="keyword">new</span> <span class="title class_">MyFactory</span>();</span><br><span class="line">        <span class="type">Team</span> <span class="variable">team</span> <span class="operator">=</span> factory.instanceFun();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p>创建新的配置文件createType.xml</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?xml version=<span class="string">&quot;1.0&quot;</span> encoding=<span class="string">&quot;UTF-8&quot;</span>?&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">beans</span> <span class="attr">xmlns</span>=<span class="string">&quot;http://www.springframework.org/schema/beans&quot;</span></span></span><br><span class="line"><span class="tag">       <span class="attr">xmlns:xsi</span>=<span class="string">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span></span></span><br><span class="line"><span class="tag">       <span class="attr">xsi:schemaLocation</span>=<span class="string">&quot;http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd&quot;</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">&lt;!--spring容器创建对象的方式：</span></span><br><span class="line"><span class="comment">        1、通过默认构造方法</span></span><br><span class="line"><span class="comment">        2、通过带参数的构造方法</span></span><br><span class="line"><span class="comment">        3、通过工厂方法：实例方法，静态方法--&gt;</span></span><br><span class="line">    <span class="comment">&lt;!--1、通过默认构造方法--&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;team1&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.kbb.pojo.Team&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br><span class="line">    <span class="comment">&lt;!-- 2、通过带参数的构造方法--&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;team2&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.kbb.pojo.Team&quot;</span>&gt;</span></span><br><span class="line">        <span class="comment">&lt;!--name:表示参数的名称--&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">constructor-arg</span> <span class="attr">name</span>=<span class="string">&quot;id&quot;</span> <span class="attr">value</span>=<span class="string">&quot;1001&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">constructor-arg</span> <span class="attr">name</span>=<span class="string">&quot;name&quot;</span> <span class="attr">value</span>=<span class="string">&quot;勇士&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">constructor-arg</span> <span class="attr">name</span>=<span class="string">&quot;location&quot;</span> <span class="attr">value</span>=<span class="string">&quot;金州&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;team3&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.kbb.pojo.Team&quot;</span>&gt;</span></span><br><span class="line">        <span class="comment">&lt;!--index:表示参数的下标索引--&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">constructor-arg</span> <span class="attr">index</span>=<span class="string">&quot;0&quot;</span> <span class="attr">value</span>=<span class="string">&quot;1002&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">constructor-arg</span> <span class="attr">index</span>=<span class="string">&quot;1&quot;</span> <span class="attr">value</span>=<span class="string">&quot;热火&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">constructor-arg</span> <span class="attr">index</span>=<span class="string">&quot;2&quot;</span> <span class="attr">value</span>=<span class="string">&quot;迈阿密&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br><span class="line">    <span class="comment">&lt;!--3、通过工厂方法：</span></span><br><span class="line"><span class="comment">   		 3.1 静态方法   </span></span><br><span class="line"><span class="comment"> 			Team team1 = MyFactory.staticFun();--&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;staticTeam&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.kbb.pojo.MyFactory&quot;</span> <span class="attr">factory-method</span>=<span class="string">&quot;staticFun&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">&lt;!--3、通过工厂方法：</span></span><br><span class="line"><span class="comment">    	3.2 实例方法</span></span><br><span class="line"><span class="comment">    	MyFactory factory=new MyFactory();</span></span><br><span class="line"><span class="comment">    	Team team = factory.instanceFun();--&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;factory&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.kbb.pojo.MyFactory&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;instanceTeam&quot;</span> <span class="attr">factory-bean</span>=<span class="string">&quot;factory&quot;</span> <span class="attr">factory-method</span>=<span class="string">&quot;instanceFun&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">beans</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>测试类：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.lina.test;</span><br><span class="line"><span class="keyword">import</span> org.junit.Test;</span><br><span class="line"><span class="keyword">import</span> org.springframework.context.ApplicationContext;</span><br><span class="line"><span class="keyword">import</span> org.springframework.context.support.ClassPathXmlApplicationContext;</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">CreateTypeTest</span> &#123;</span><br><span class="line">    <span class="meta">@Test</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">test01</span><span class="params">()</span>&#123;</span><br><span class="line">        ApplicationContext ac=<span class="keyword">new</span> <span class="title class_">ClassPathXmlApplicationContext</span>(<span class="string">&quot;createType.xml&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>测试结果：</p>
<p><img src="/img%5Cimage-20210317183508741.png" class="lazyload" data-srcset="/img%5Cimage-20210317183508741.png" srcset="" alt="image-20210317183508741"></p>
<h2 id="2-4-基于XML的DI"><a href="#2-4-基于XML的DI" class="headerlink" title="2.4 基于XML的DI"></a>2.4 基于XML的DI</h2><p>DI—Dependency Injection，即“依赖注入”：是组件之间依赖关系由容器在运行期决定，形象的说，即由容器动态的将某个依赖关系注入到组件之中。依赖注入的目的并非为软件系统带来更多功能，而是为了提升组件重用的频率，并为系统搭建一个灵活、可扩展的平台。通过依赖注入机制，我们只需要通过简单的配置，而无需任何代码就可指定目标需要的资源，完成自身的业务逻辑，而不需要关心具体的资源来自何处，由谁实现。</p>
<p>IoC 是一个概念，是一种思想，其实现方式多种多样。依赖注入就是其中用的比较多的一种方式。</p>
<p><strong>Ioc和DI是同一个概念的不同角度描述</strong>。IoC是一种思想，概念，DI是实现它的手段。Spring框架使用依赖注入实现IoC.</p>
<p>Spring 容器是一个超级大工厂，负责创建、管理所有的 Java 对象，这些 Java 对象被称为 Bean。Spring 容器管理着容器中 Bean 之间的依赖关系，Spring 使用“依赖注入”的方式来管理 Bean 之间的依赖关系。使用 IoC 实现对象之间的解耦和。</p>
<h3 id="2-4-1-注入分类"><a href="#2-4-1-注入分类" class="headerlink" title="2.4.1 注入分类"></a>2.4.1 注入分类</h3><p>bean 实例在调用无参构造器创建对象后，就要对 bean 对象的属性进行初始化。初始化是由容器自动完成的，称为注入。</p>
<h4 id="2-4-1-1-通过set方法"><a href="#2-4-1-1-通过set方法" class="headerlink" title="2.4.1.1 通过set方法"></a>2.4.1.1 通过set方法</h4><p>set 注入也叫设值注入是指，通过 setter 方法传入被调用者的实例。这种注入方式简单、直观，因而在 Spring 的依赖注入中大量使用。</p>
<h4 id="2-4-1-2-通过构造方法"><a href="#2-4-1-2-通过构造方法" class="headerlink" title="2.4.1.2 通过构造方法"></a>2.4.1.2 通过构造方法</h4><p>构造注入是指，在构造调用者实例的同时，完成被调用者的实例化。使用构造器设置依赖关系。</p>
<h4 id="2-4-1-3-自动注入"><a href="#2-4-1-3-自动注入" class="headerlink" title="2.4.1.3. 自动注入"></a>2.4.1.3. 自动注入</h4><p>对于引用类型属性的注入，也可不在配置文件中显示的注入。可以通过为<bean/>标签</p>
<p>设置 autowire 属性值，为引用类型属性进行隐式自动注入（默认是不自动注入引用类型属 性）。根据自动注入判断标准的不同，可以分为两种：</p>
<p>byName：根据名称自动注入</p>
<p>byType： 根据类型自动注入</p>
<h5 id="1、-byName"><a href="#1、-byName" class="headerlink" title="1、 byName"></a>1、 byName</h5><p>当配置文件中被调用者 bean 的 id 值与代码中调用者 bean 类的属性名相同时，可使用byName 方式，让容器自动将被调用者 bean 注入给调用者 bean。容器是通过调用者的 bean类的属性名与配置文件的被调用者 bean 的 id 进行比较而实现自动注入的。</p>
<h5 id="2、-byType"><a href="#2、-byType" class="headerlink" title="2、 byType"></a>2、 byType</h5><p>使用 byType 方式自动注入，要求：配置文件中被调用者 bean 的 class 属性指定的类，要与代码中调用者 bean 类的某引用类型属性类型同源。即要么相同，要么有 is-a 关系（子类，或是实现类）。但这样的同源的被调用 bean 只能有一个。多于一个，容器就不知该匹配哪一个了。</p>
<p>示例：</p>
<p>创建TeamDao.java</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.lina.dao;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">TeamDao</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">add</span><span class="params">()</span>&#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;TeamDao---- add----&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>创建TeamService.java</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.lina.service;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.lina.dao.TeamDao;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">TeamService</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> TeamDao teamDao;<span class="comment">//=new TeamDao();</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">add</span><span class="params">()</span>&#123;</span><br><span class="line">        teamDao.add();</span><br><span class="line">        System.out.println(<span class="string">&quot;TeamService----add----&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">TeamService</span><span class="params">()</span> &#123;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">TeamService</span><span class="params">(TeamDao teamDao)</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>.teamDao = teamDao;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> TeamDao <span class="title function_">getTeamDao</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> teamDao;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">setTeamDao</span><span class="params">(TeamDao teamDao)</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>.teamDao = teamDao;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p>创建配置文件DI.xml</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?xml version=<span class="string">&quot;1.0&quot;</span> encoding=<span class="string">&quot;UTF-8&quot;</span>?&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">beans</span> <span class="attr">xmlns</span>=<span class="string">&quot;http://www.springframework.org/schema/beans&quot;</span></span></span><br><span class="line"><span class="tag">       <span class="attr">xmlns:xsi</span>=<span class="string">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span></span></span><br><span class="line"><span class="tag">       <span class="attr">xsi:schemaLocation</span>=<span class="string">&quot;http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd&quot;</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;teamDao&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.lina.dao.TeamDao&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br><span class="line">   <span class="comment">&lt;!-- &lt;bean id=&quot;teamDao1&quot; class=&quot;com.lina.dao.TeamDao&quot;&gt;&lt;/bean&gt;--&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;teamService&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.lina.service.TeamService&quot;</span>&gt;</span></span><br><span class="line">        <span class="comment">&lt;!--使用set方法注入属性值 注意 这里需要在service方法中提供一个setter方法--&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;teamDao&quot;</span> <span class="attr">ref</span>=<span class="string">&quot;teamDao&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">property</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;teamService2&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.lina.service.TeamService&quot;</span>&gt;</span></span><br><span class="line">        <span class="comment">&lt;!--使用构造方法注入属性值 需要提供一个构造器--&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">constructor-arg</span> <span class="attr">name</span>=<span class="string">&quot;teamDao&quot;</span> <span class="attr">ref</span>=<span class="string">&quot;teamDao&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">constructor-arg</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br><span class="line">    </span><br><span class="line">    </span><br><span class="line">    <span class="comment">&lt;!--按名称自动注入：查找容器中id名与属性名一致的对象 也就是上面是teamDao 那id也得一样 进行注入--&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;teamService3&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.lina.service.TeamService&quot;</span> <span class="attr">autowire</span>=<span class="string">&quot;byName&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">&lt;!--按类型自动注入：查找容器中类型与属性类型相同或者符合is-a关系的对象进行注入，但是要求类型相同的对象唯一，否则抛出异常：不知道用哪一个匹配--&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;teamService4&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.lina.service.TeamService&quot;</span> <span class="attr">autowire</span>=<span class="string">&quot;byType&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;/<span class="name">beans</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>创建测试类：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.lina.test;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.lina.dao.TeamDao;</span><br><span class="line"><span class="keyword">import</span> com.lina.service.TeamService;</span><br><span class="line"><span class="keyword">import</span> org.junit.Test;</span><br><span class="line"><span class="keyword">import</span> org.springframework.context.ApplicationContext;</span><br><span class="line"><span class="keyword">import</span> org.springframework.context.support.ClassPathXmlApplicationContext;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Test02</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Test</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">test02</span><span class="params">()</span>&#123;</span><br><span class="line">        ApplicationContext ac=<span class="keyword">new</span> <span class="title class_">ClassPathXmlApplicationContext</span>(<span class="string">&quot;DI.xml&quot;</span>);</span><br><span class="line">        <span class="type">TeamService</span> <span class="variable">teamService</span> <span class="operator">=</span> (TeamService) ac.getBean(<span class="string">&quot;teamService&quot;</span>);</span><br><span class="line">        teamService.add();</span><br><span class="line"></span><br><span class="line">        <span class="type">TeamService</span> <span class="variable">teamService2</span> <span class="operator">=</span> (TeamService) ac.getBean(<span class="string">&quot;teamService2&quot;</span>);</span><br><span class="line">        teamService2.add();</span><br><span class="line"></span><br><span class="line">        <span class="type">TeamService</span> <span class="variable">teamService3</span> <span class="operator">=</span> (TeamService) ac.getBean(<span class="string">&quot;teamService3&quot;</span>);</span><br><span class="line">        teamService3.add();</span><br><span class="line"></span><br><span class="line">        <span class="type">TeamService</span> <span class="variable">teamService4</span> <span class="operator">=</span> (TeamService) ac.getBean(<span class="string">&quot;teamService4&quot;</span>);</span><br><span class="line">        teamService4.add();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Test</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">test01</span><span class="params">()</span>&#123;</span><br><span class="line">        TeamDao teamDao=<span class="keyword">new</span> <span class="title class_">TeamDao</span>();</span><br><span class="line">        TeamService teamService=<span class="keyword">new</span> <span class="title class_">TeamService</span>();</span><br><span class="line">        teamService.setTeamDao(teamDao);</span><br><span class="line">        teamService.add();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<h2 id="2-5、基于注解实现IoC–重要"><a href="#2-5、基于注解实现IoC–重要" class="headerlink" title="2.5、基于注解实现IoC–重要"></a>2.5、基于注解实现IoC–重要</h2><p>对于 DI 使用注解，将不再需要在 Spring 配置文件中声明 bean 实例。</p>
<h3 id="2-5-1-声明Bean的注解-Component"><a href="#2-5-1-声明Bean的注解-Component" class="headerlink" title="2.5.1 声明Bean的注解 @Component"></a>2.5.1 声明Bean的注解 @Component</h3><p>在类上添加注解@Component表示该类创建对象的权限交给Spring容器。注解的value属性用于指定bean的id值，value可以省略。</p>
<p>@Component 不指定 value 属性，bean 的 id 是类名的首字母小写。</p>
<p><img src="/img%5Cimage-20210318140203847.png" class="lazyload" data-srcset="/img%5Cimage-20210318140203847.png" srcset="" alt="image-20210318140203847"></p>
<p>除此之外，Spring中还提供了其他3个用于创建对象的注解：</p>
<p><strong>@Repository : 用于dao实现类的的注解</strong></p>
<p><strong>@Service: 用户service实现类的注解</strong></p>
<p><strong>@Controller: 用于controller实现类的注解</strong></p>
<p>这三个注解与@Component 都可以创建对象，但这三个注解还有其他的含义，@Service创建业务层对象，业务层对象可以加入事务功能，@Controller 注解创建的对象可以作为处理器接收用户的请求。</p>
<p>@Repository，@Service，@Controller 是对@Component 注解的细化，标注不同层的对象。即持久层对象，业务层对象，控制层对象。</p>
<p><img src="/img%5Cimage-20210318140517621.png" class="lazyload" data-srcset="/img%5Cimage-20210318140517621.png" srcset="" alt="image-20210318140625613"></p>
<h3 id="2-5-2-包扫描"><a href="#2-5-2-包扫描" class="headerlink" title="2.5.2 包扫描"></a>2.5.2 包扫描</h3><p>需要在 Spring 配置文件中配置组件扫描器，用于在指定的基本包中扫描注解。<strong>如果没有包扫描，添加的创建对象的注解不生效</strong>。</p>
<p>如果要扫描的包有多个，可以有以下方式扫描：</p>
<p><strong>1、使用多个context:component-scan指定不同的包路径</strong></p>
<p><img src="/img%5Cimage-20210318140404062.png" class="lazyload" data-srcset="/img%5Cimage-20210318140404062.png" srcset="" alt="image-20210318140404062"></p>
<p><strong>2、指定 base-package的值使用分隔符</strong></p>
<p>分隔符可以使用逗号（，）分号（；）还可以使用空格，不建议使用空格。</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!--多个包的扫描: 方式2 ： base-package中直接声明要扫描的多个包 ，多个值用逗号,分号或者空格分割，但是空格不推荐--&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">context:component-scan</span> <span class="attr">base-package</span>=<span class="string">&quot;com.lina.dao,com.lina.service,com.lina.controller&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">context:component-scan</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p><strong>3、base-package是指定到父包名</strong></p>
<p>base-package 的值表是基本包，容器启动会扫描包及其子包中的注解，当然也会扫描到子包下级的子包。所以 base-package 可以指定一个父包就可以。</p>
<p>但不建议使用顶级的父包，扫描的路径比较多，导致容器启动时间变慢。指定到目标包和合适的。也就是注解所在包全路径。</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!--多个包的扫描: 方式3： base-package中直接声明要扫描的多个包的父包--&gt;</span></span><br><span class="line">   <span class="tag">&lt;<span class="name">context:component-scan</span> <span class="attr">base-package</span>=<span class="string">&quot;com.lina&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">context:component-scan</span>&gt;</span></span><br></pre></td></tr></table></figure>

<h3 id="2-5-3-属性注入-Vaule"><a href="#2-5-3-属性注入-Vaule" class="headerlink" title="2.5.3 属性注入@Vaule"></a>2.5.3 属性注入@Vaule</h3><p>需要在属性上使用注解@Value，该注解的 value 属性用于指定要注入的值。使用该注解完成属性注入时，类中无需 setter。当然，若属性有 setter，则也可将其加到 setter 上。</p>
<p><img src="/img%5Cimage-20210318163450543.png" class="lazyload" data-srcset="/img%5Cimage-20210318163450543.png" srcset="" alt="image-20210318163450543"></p>
<h3 id="2-5-4-byType自动注入-Autowired"><a href="#2-5-4-byType自动注入-Autowired" class="headerlink" title="2.5.4 byType自动注入@Autowired"></a>2.5.4 byType自动注入@Autowired</h3><p>需要在引用属性上使用注解@Autowired，该注解默认使用按类型自动装配 Bean 的方式。使用该注解完成属性注入时，类中无需 setter。当然，若属性有 setter，则也可将其加到 setter 上。</p>
<h3 id="2-5-5-byName自动注入-Autowired和-Qualifier"><a href="#2-5-5-byName自动注入-Autowired和-Qualifier" class="headerlink" title="2.5.5 byName自动注入@Autowired和@Qualifier"></a>2.5.5 byName自动注入@Autowired和@Qualifier</h3><p>需要在引用属性上联合使用注解@Autowired 与@Qualifier。@Qualifier 的 value 属性用于指定要匹配的 Bean 的 id 值。类中无需 set 方法，也可加到 set 方法上。</p>
<p>@Autowired 还有一个属性 required，默认值为 true，表示当匹配失败后，会终止程序运行。若将其值设置为 false，则匹配失败，将被忽略，未匹配的属性值为 null。</p>
<p><img src="/img%5Cimage-20210318163605579.png" class="lazyload" data-srcset="/img%5Cimage-20210318163605579.png" srcset="" alt="image-20210318163605579"></p>
<h3 id="2-5-6-自动注入-Resource"><a href="#2-5-6-自动注入-Resource" class="headerlink" title="2.5.6 自动注入@Resource"></a>2.5.6 自动注入@Resource</h3><p>Spring提供了对 <strong>jdk中@Resource注解</strong>的支持。@Resource 注解既可以按名称匹配Bean，也可以按类型匹配 Bean。<strong>默认是按名称注入</strong>。使用该注解，要求 JDK 必须是 6 及以上版本。@Resource 可在属性上，也可在 set 方法上。</p>
<h4 id="1、byType注入引用类型属性"><a href="#1、byType注入引用类型属性" class="headerlink" title="1、byType注入引用类型属性"></a>1、byType注入引用类型属性</h4><p>@Resource 注解若不带任何参数，采用默认按名称的方式注入，按名称不能注入 bean，则会按照类型进行 Bean 的匹配注入。</p>
<h4 id="2、byName注入引用类型属性"><a href="#2、byName注入引用类型属性" class="headerlink" title="2、byName注入引用类型属性"></a>2、byName注入引用类型属性</h4><p>@Resource 注解指定其 name 属性，则 name 的值即为按照名称进行匹配的 Bean 的 id。</p>
<p><img src="/img%5Cimage-20210318163747884.png" class="lazyload" data-srcset="/img%5Cimage-20210318163747884.png" srcset="" alt="image-20210318163747884"></p>
<h1 id="3、Spring核心之AOP"><a href="#3、Spring核心之AOP" class="headerlink" title="3、Spring核心之AOP"></a>3、Spring核心之AOP</h1><h2 id="3-1-什么是AOP"><a href="#3-1-什么是AOP" class="headerlink" title="3.1 什么是AOP"></a>3.1 什么是AOP</h2><p>AOP为Aspect Oriented Programming的缩写，意思为<strong>面向切面编程</strong>，是通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。</p>
<p>AOP的作用：不修改源码的情况下，程序运行期间对方法进行功能增强</p>
<p>好处：1、减少代码的重复，提高开发效率，便于维护。</p>
<p>​			 2、专注核心业务的开发。</p>
<p>核心业务和服务性代码混合在一起 </p>
<p>开发中：各自做自己擅长的事情，运行的时候将服务性代码织入到核心业务中。 </p>
<p>通过spring工厂自动实现将服务性代码以切面的方式加入到核心业务代码中。</p>
<h2 id="3-2-AOP的实现机制-动态代理"><a href="#3-2-AOP的实现机制-动态代理" class="headerlink" title="3.2 AOP的实现机制-动态代理"></a>3.2 AOP的实现机制-动态代理</h2><h4 id="3-2-1-什么是代理模式"><a href="#3-2-1-什么是代理模式" class="headerlink" title="3.2.1 什么是代理模式"></a>3.2.1 什么是代理模式</h4><p>代理：自己不做，找人帮你做。</p>
<p>代理模式：在一个原有功能的基础上添加新的功能。</p>
<p>分类：静态代理和动态代理。</p>
<h2 id="3-3静态代理"><a href="#3-3静态代理" class="headerlink" title="3.3静态代理"></a>3.3静态代理</h2><h3 id="3-3-1-原有方式：核心业务和服务方法都编写在一起"><a href="#3-3-1-原有方式：核心业务和服务方法都编写在一起" class="headerlink" title="3.3.1 原有方式：核心业务和服务方法都编写在一起"></a>3.3.1 原有方式：核心业务和服务方法都编写在一起</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span>  com.lina.service;</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">TeamService</span> &#123;</span><br><span class="line">	<span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">add</span><span class="params">()</span>&#123;</span><br><span class="line">		<span class="keyword">try</span> &#123;</span><br><span class="line">			System.out.println(<span class="string">&quot;开始事务&quot;</span>);</span><br><span class="line">			System.out.println(<span class="string">&quot;TeamService---- add----&quot;</span>);<span class="comment">// 核心业务</span></span><br><span class="line">			System.out.println(<span class="string">&quot;提交事务&quot;</span>);</span><br><span class="line">		&#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">			e.printStackTrace();</span><br><span class="line">			System.out.println(<span class="string">&quot;回滚事务&quot;</span>);</span><br><span class="line">		&#125;</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="3-3-2-基于类的静态代理"><a href="#3-3-2-基于类的静态代理" class="headerlink" title="3.3.2 基于类的静态代理"></a>3.3.2 基于类的静态代理</h3><p>将服务性代码分离出来，核心业务–保存业务中只有保存功能</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span>  com.lina.service;</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">TeamService</span> &#123;</span><br><span class="line">	<span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">add</span><span class="params">()</span>&#123;</span><br><span class="line">		System.out.println(<span class="string">&quot;TeamService---- add----&quot;</span>);<span class="comment">// 核心业务</span></span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.lina.staticproxy;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.lina.service.TeamService;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 基于类的静态代理：</span></span><br><span class="line"><span class="comment"> *     要求继承被代理的类</span></span><br><span class="line"><span class="comment"> *     弊端：每次只能代理一个类</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">ProxyTeamService</span> <span class="keyword">extends</span> <span class="title class_">TeamService</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">add</span><span class="params">()</span>&#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;开始事务&quot;</span>);</span><br><span class="line">            <span class="built_in">super</span>.add();<span class="comment">//核心业务就是由被代理对象完成 ；其他服务功能由代理类完成</span></span><br><span class="line">            System.out.println(<span class="string">&quot;提交事务&quot;</span>);</span><br><span class="line">        &#125;<span class="keyword">catch</span> (Exception e)&#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;回滚事务&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">		TeamService ser=<span class="keyword">new</span> <span class="title class_">ProxyTeamService</span>();</span><br><span class="line">		ser.add();</span><br><span class="line">	&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>弊端：代理类只能代理一个类</p>
</blockquote>
<h3 id="3-3-3-基于接口的静态代理"><a href="#3-3-3-基于接口的静态代理" class="headerlink" title="3.3.3 基于接口的静态代理"></a>3.3.3 基于接口的静态代理</h3><p>为核心业务（保存add）创建一个接口,通过接口暴露被代理的方法</p>
<p>要求：代理类和被代理类都实现了同一个接口</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.lina.service;</span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 接口定义核心方法</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">interface</span> <span class="title class_">IService</span> &#123;</span><br><span class="line">    <span class="keyword">void</span> <span class="title function_">add</span><span class="params">()</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span>  com.lina.service;</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">TeamService</span> <span class="keyword">implements</span> <span class="title class_">IService</span>&#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">add</span><span class="params">()</span>&#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;TeamService---- add----&quot;</span>);<span class="comment">// 核心业务</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">package</span> com.lina.service;</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">UserService</span> <span class="keyword">implements</span> <span class="title class_">IService</span>&#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">add</span><span class="params">()</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;UserService---- add-----&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.lina.staticproxy;</span><br><span class="line"><span class="keyword">import</span> com.lina.service.IService;</span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 基于接口的静态代理：</span></span><br><span class="line"><span class="comment"> * 代理类和被代理类实现同一个接口</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">ProxyTranService</span> <span class="keyword">implements</span> <span class="title class_">IService</span> &#123;</span><br><span class="line">    <span class="keyword">private</span> IService service;<span class="comment">//被代理的对象</span></span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">ProxyTranService</span><span class="params">(IService service)</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>.service = service;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">add</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;开始事务&quot;</span>);</span><br><span class="line">           service.add();<span class="comment">//核心业务就是由被代理对象完成 ；其他服务功能由代理类完成</span></span><br><span class="line">            System.out.println(<span class="string">&quot;提交事务&quot;</span>);</span><br><span class="line">        &#125;<span class="keyword">catch</span> (Exception e)&#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;回滚事务&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.lina.staticproxy;</span><br><span class="line"><span class="keyword">import</span> com.lina.service.IService;</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">ProxyLogService</span> <span class="keyword">implements</span> <span class="title class_">IService</span> &#123;</span><br><span class="line">    <span class="keyword">private</span> IService service;<span class="comment">//被代理对象</span></span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">ProxyLogService</span><span class="params">(IService service)</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>.service = service;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">add</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;开始日志&quot;</span>);</span><br><span class="line">            service.add();<span class="comment">//核心业务就是由被代理对象完成 ；其他服务功能由代理类完成</span></span><br><span class="line">            System.out.println(<span class="string">&quot;结束日志&quot;</span>);</span><br><span class="line">        &#125;<span class="keyword">catch</span> (Exception e)&#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;异常日志&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>测试类：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">       TeamService teamService=<span class="keyword">new</span> <span class="title class_">TeamService</span>();<span class="comment">//被代理对象</span></span><br><span class="line">       UserService userService=<span class="keyword">new</span> <span class="title class_">UserService</span>();<span class="comment">//被代理对象</span></span><br><span class="line"></span><br><span class="line">       ProxyTranService tranService=<span class="keyword">new</span> <span class="title class_">ProxyTranService</span>(userService);<span class="comment">//事务代理对象--一级代理</span></span><br><span class="line">       <span class="comment">//tranService.add();//代理对象干活</span></span><br><span class="line"></span><br><span class="line">       ProxyLogService logService=<span class="keyword">new</span> <span class="title class_">ProxyLogService</span>(tranService);<span class="comment">//日志的代理对象--二级代理</span></span><br><span class="line">       logService.add();</span><br><span class="line">   &#125;</span><br></pre></td></tr></table></figure>

<h3 id="3-3-4-提取出切面代码，作为AOP接口"><a href="#3-3-4-提取出切面代码，作为AOP接口" class="headerlink" title="3.3.4 提取出切面代码，作为AOP接口"></a>3.3.4 提取出切面代码，作为AOP接口</h3><p>共有4个位置可以将切面代码编织进入核心业务代码中。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.lina.aop;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 切面：服务代码，切入到核心代码中,切入到哪里，给了四个位置</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">interface</span> <span class="title class_">AOP</span> &#123;</span><br><span class="line">    <span class="keyword">void</span> <span class="title function_">before</span><span class="params">()</span>;</span><br><span class="line">    <span class="keyword">void</span> <span class="title function_">after</span><span class="params">()</span>;</span><br><span class="line">    <span class="keyword">void</span> <span class="title function_">exception</span><span class="params">()</span>;</span><br><span class="line">    <span class="keyword">void</span> <span class="title function_">myFinally</span><span class="params">()</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.lina.aop;</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">TranAOP</span> <span class="keyword">implements</span> <span class="title class_">AOP</span> &#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">before</span><span class="params">()</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;事务----before&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">after</span><span class="params">()</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;事务----after&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">exception</span><span class="params">()</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;事务----exception&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">myFinally</span><span class="params">()</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;事务----myFinally&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.lina.aop;</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">LogAop</span> <span class="keyword">implements</span> <span class="title class_">AOP</span>&#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">before</span><span class="params">()</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;日志----before&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">after</span><span class="params">()</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;日志----after&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">exception</span><span class="params">()</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;日志----exception&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">myFinally</span><span class="params">()</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;日志----myFinally&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.lina.staticproxy;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.lina.aop.AOP;</span><br><span class="line"><span class="keyword">import</span> com.lina.service.IService;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">ProxyAOPService</span> <span class="keyword">implements</span> <span class="title class_">IService</span> &#123;</span><br><span class="line">    <span class="keyword">private</span> IService service;<span class="comment">//被代理对象</span></span><br><span class="line">    <span class="keyword">private</span> AOP aop;<span class="comment">//要加入切面</span></span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">ProxyAOPService</span><span class="params">(IService service, AOP aop)</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>.service = service;</span><br><span class="line">        <span class="built_in">this</span>.aop = aop;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">add</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            aop.before();</span><br><span class="line">            service.add();<span class="comment">//被代理对象干活</span></span><br><span class="line">            aop.after();</span><br><span class="line">        &#125;<span class="keyword">catch</span> (Exception e)&#123;</span><br><span class="line">            aop.exception();</span><br><span class="line">        &#125;<span class="keyword">finally</span> &#123;</span><br><span class="line">            aop.myFinally();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Test</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">test02</span><span class="params">()</span>&#123;</span><br><span class="line">        IService teamService=<span class="keyword">new</span> <span class="title class_">TeamService</span>();<span class="comment">//被代理对象--核心内容</span></span><br><span class="line">        AOP logAop=<span class="keyword">new</span> <span class="title class_">LogAop</span>();<span class="comment">//切面-服务内容</span></span><br><span class="line">        AOP tranAop=<span class="keyword">new</span> <span class="title class_">TranAOP</span>();</span><br><span class="line">        IService service=<span class="keyword">new</span> <span class="title class_">ProxyAOPService</span>(teamService,logAop); <span class="comment">//代理对象--一级代理</span></span><br><span class="line">        IService service2=<span class="keyword">new</span> <span class="title class_">ProxyAOPService</span>(service,tranAop);<span class="comment">//代理对象--二级代理</span></span><br><span class="line">        service2.add();</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>

<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">总结静态代理：</span><br><span class="line">    1）可以做到在不修改目标对象的功能前提下，对目标对象功能扩展。</span><br><span class="line">    2）缺点：</span><br><span class="line">        因为代理对象，需要与目标对象实现一样的接口。所以会有很多代理类，类太多。</span><br><span class="line">         一旦接口增加方法，目标对象与代理对象都要维护。</span><br></pre></td></tr></table></figure>

<h2 id="3-4-动态代理"><a href="#3-4-动态代理" class="headerlink" title="3.4 动态代理"></a>3.4 动态代理</h2><p>静态代理：要求代理类一定存在，</p>
<p>动态代理：程序运行的时候，根据要被代理的对象动态生成代理类。</p>
<p>类型：1、基于JDK的动态代理</p>
<p>​			2、基于CGLIB的动态代理</p>
<h3 id="3-4-1-基于JDK的动态代理"><a href="#3-4-1-基于JDK的动态代理" class="headerlink" title="3.4.1 基于JDK的动态代理"></a>3.4.1 基于JDK的动态代理</h3><p><img src="/img%5Cimage-20210315185849898.png" class="lazyload" data-srcset="/img%5Cimage-20210315185849898.png" srcset="" alt="image-20210315185849898"></p>
<h4 id="3-4-1-1-直接编写测试类"><a href="#3-4-1-1-直接编写测试类" class="headerlink" title="3.4.1.1 直接编写测试类"></a>3.4.1.1 直接编写测试类</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*newProxyInstance(ClassLoader loader, Class&lt;?&gt;[] interfaces, InvocationHandler h) </span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">ClassLoader ：类加载器，因为动态代理类，借助别人的类加载器。一般使用被代理对象的类加载器。</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">Class&lt;?&gt;[] interfaces:接口类对象的集合，针对接口的代理，针对哪个接口做代理，一般使用的就是被代理对象的接口。</span></span><br><span class="line"><span class="comment">InvocationHandler：句柄，回调函数，编写代理的规则代码</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">public Object invoke(Object arg0, Method arg1, Object[] arg2)</span></span><br><span class="line"><span class="comment">Object arg0：代理对象</span></span><br><span class="line"><span class="comment"> Method arg1：被代理的方法</span></span><br><span class="line"><span class="comment"> Object[] arg2：被代理方法被执行的时候的参数的数组</span></span><br><span class="line"><span class="comment"> */</span></span><br></pre></td></tr></table></figure>

<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.lina.dynamicproxy;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.lina.service.IService;</span><br><span class="line"><span class="keyword">import</span> com.lina.service.TeamService;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.InvocationHandler;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.Method;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.Proxy;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">MyJDKProxy</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">        <span class="comment">//目标对象--被代理对象</span></span><br><span class="line">        TeamService teamService=<span class="keyword">new</span> <span class="title class_">TeamService</span>();</span><br><span class="line">        <span class="comment">//返回代理对象 调用JDK中Proxy类中的静态方法newProxyInstance获取动态代理类的实例</span></span><br><span class="line">        IService proxyService= (IService) Proxy.newProxyInstance(</span><br><span class="line">                teamService.getClass().getClassLoader(),</span><br><span class="line">                teamService.getClass().getInterfaces(),</span><br><span class="line">                <span class="keyword">new</span> <span class="title class_">InvocationHandler</span>() &#123;<span class="comment">//回调函数 编写代理规则</span></span><br><span class="line">                    <span class="meta">@Override</span></span><br><span class="line">                    <span class="keyword">public</span> Object <span class="title function_">invoke</span><span class="params">(Object proxy, Method method, Object[] args)</span> <span class="keyword">throws</span> Throwable &#123;</span><br><span class="line">                        <span class="keyword">try</span> &#123;</span><br><span class="line">                            System.out.println(<span class="string">&quot;开始事务&quot;</span>);</span><br><span class="line">                            <span class="type">Object</span> <span class="variable">invoke</span> <span class="operator">=</span> method.invoke(teamService, args);<span class="comment">//核心业务</span></span><br><span class="line">                            System.out.println(<span class="string">&quot;提交事务&quot;</span>);</span><br><span class="line">                            <span class="keyword">return</span> invoke;</span><br><span class="line">                        &#125;<span class="keyword">catch</span> (Exception e)&#123;</span><br><span class="line">                            System.out.println(<span class="string">&quot;回滚事务&quot;</span>);</span><br><span class="line">                            e.printStackTrace();</span><br><span class="line">                            <span class="keyword">throw</span> e;</span><br><span class="line">                        &#125;<span class="keyword">finally</span> &#123;</span><br><span class="line">                            System.out.println(<span class="string">&quot;finally---------&quot;</span>);</span><br><span class="line">                        &#125;</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;</span><br><span class="line">        );</span><br><span class="line">        <span class="comment">//代理对象干活</span></span><br><span class="line">        proxyService.add();</span><br><span class="line">        System.out.println(teamService.getClass());</span><br><span class="line">		System.out.println(proxyService.getClass()+<span class="string">&quot;--------&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<h4 id="3-4-1-2-结构化设计"><a href="#3-4-1-2-结构化设计" class="headerlink" title="3.4.1.2 结构化设计"></a>3.4.1.2 结构化设计</h4><p>方式1：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.lina.dynamicproxy;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.lina.aop.AOP;</span><br><span class="line"><span class="keyword">import</span> com.lina.service.IService;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.InvocationHandler;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.Method;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">ProxyHandler</span> <span class="keyword">implements</span> <span class="title class_">InvocationHandler</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> IService service;<span class="comment">//目标对象</span></span><br><span class="line">    <span class="keyword">private</span> AOP aop;<span class="comment">//切面</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">ProxyHandler</span><span class="params">(IService service, AOP aop)</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>.service = service;</span><br><span class="line">        <span class="built_in">this</span>.aop = aop;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> Object <span class="title function_">invoke</span><span class="params">(Object proxy, Method method, Object[] args)</span> <span class="keyword">throws</span> Throwable &#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">           aop.before();</span><br><span class="line">            <span class="type">Object</span> <span class="variable">invoke</span> <span class="operator">=</span> method.invoke(service, args);<span class="comment">//核心业务</span></span><br><span class="line">            aop.after();</span><br><span class="line">            <span class="keyword">return</span> invoke;</span><br><span class="line">        &#125;<span class="keyword">catch</span> (Exception e)&#123;</span><br><span class="line">            aop.exception();</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">            <span class="keyword">throw</span> e;</span><br><span class="line">        &#125;<span class="keyword">finally</span> &#123;</span><br><span class="line">            aop.myFinally();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main2</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">        <span class="comment">//目标对象--被代理对象</span></span><br><span class="line">        TeamService teamService=<span class="keyword">new</span> <span class="title class_">TeamService</span>();</span><br><span class="line">        <span class="comment">//切面</span></span><br><span class="line">        AOP tranAop=<span class="keyword">new</span> <span class="title class_">TranAOP</span>();</span><br><span class="line">        <span class="comment">//返回代理对象 基于JDK的动态代理</span></span><br><span class="line">        IService proxyService= (IService) Proxy.newProxyInstance(</span><br><span class="line">                teamService.getClass().getClassLoader(),</span><br><span class="line">                teamService.getClass().getInterfaces(),</span><br><span class="line">                <span class="keyword">new</span> <span class="title class_">ProxyHandler</span>(teamService,tranAop)</span><br><span class="line">        );</span><br><span class="line">        <span class="comment">//代理对象干活</span></span><br><span class="line">        proxyService.add();</span><br><span class="line">        System.out.println(teamService.getClass());</span><br><span class="line">        System.out.println(proxyService.getClass()+<span class="string">&quot;------&quot;</span>);</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>

<p>方式2：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.lina.dynamicproxy;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.lina.aop.AOP;</span><br><span class="line"><span class="keyword">import</span> com.lina.service.IService;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.InvocationHandler;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.Method;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.Proxy;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">ProxyFactory</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> IService service;<span class="comment">//目标对象</span></span><br><span class="line">    <span class="keyword">private</span> AOP aop;<span class="comment">//切面</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">ProxyFactory</span><span class="params">(IService service, AOP aop)</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>.service = service;</span><br><span class="line">        <span class="built_in">this</span>.aop = aop;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 获取动态代理的示例</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> Object <span class="title function_">getProxyInstance</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> Proxy.newProxyInstance(</span><br><span class="line">                service.getClass().getClassLoader(),</span><br><span class="line">                service.getClass().getInterfaces(),</span><br><span class="line">                <span class="keyword">new</span> <span class="title class_">InvocationHandler</span>() &#123;<span class="comment">//回调函数 编写代理规则</span></span><br><span class="line">                    <span class="meta">@Override</span></span><br><span class="line">                    <span class="keyword">public</span> Object <span class="title function_">invoke</span><span class="params">(Object proxy, Method method, Object[] args)</span> <span class="keyword">throws</span> Throwable &#123;</span><br><span class="line">                        <span class="keyword">try</span> &#123;</span><br><span class="line">                            aop.before();</span><br><span class="line">                            <span class="type">Object</span> <span class="variable">invoke</span> <span class="operator">=</span> method.invoke(service, args);<span class="comment">//核心业务</span></span><br><span class="line">                            aop.after();</span><br><span class="line">                            <span class="keyword">return</span> invoke;</span><br><span class="line">                        &#125;<span class="keyword">catch</span> (Exception e)&#123;</span><br><span class="line">                            aop.exception();</span><br><span class="line">                            e.printStackTrace();</span><br><span class="line">                            <span class="keyword">throw</span> e;</span><br><span class="line">                        &#125;<span class="keyword">finally</span> &#123;</span><br><span class="line">                            aop.myFinally();</span><br><span class="line">                        &#125;</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;</span><br><span class="line">        );</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">        <span class="comment">//目标对象--被代理对象</span></span><br><span class="line">        TeamService teamService=<span class="keyword">new</span> <span class="title class_">TeamService</span>();</span><br><span class="line">        <span class="comment">//切面</span></span><br><span class="line">        AOP tranAop=<span class="keyword">new</span> <span class="title class_">TranAOP</span>();</span><br><span class="line">        AOP logAop=<span class="keyword">new</span> <span class="title class_">LogAop</span>();</span><br><span class="line">        <span class="comment">//获取代理对象</span></span><br><span class="line">        IService service= (IService) <span class="keyword">new</span> <span class="title class_">ProxyFactory</span>(teamService,tranAop).getProxyInstance();</span><br><span class="line">        IService service1= (IService) <span class="keyword">new</span> <span class="title class_">ProxyFactory</span>(service,logAop).getProxyInstance();</span><br><span class="line">        service1.add();<span class="comment">//核心业务+服务代码混合在一起的完整的业务方法</span></span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>

<p>代理对象不需要实现接口，但是目标对象一定要实现接口；否则不能用JDK动态代理<br>如果想要功能扩展，但目标对象没有实现接口，怎样功能扩展？</p>
<p>子类的方式实现代理CGLIB。</p>
<h3 id="3-4-2-基于CGLIB的动态代理"><a href="#3-4-2-基于CGLIB的动态代理" class="headerlink" title="3.4.2 基于CGLIB的动态代理"></a>3.4.2 基于CGLIB的动态代理</h3><p>Cglib代理，也叫做子类代理。在内存中构建一个子类对象从而实现对目标对象功能的扩展。</p>
<ul>
<li><p>JDK的动态代理有一个限制，就是使用动态代理的对象必须实现一个或多个接口。如果想代理没有实现接口的类，就可以使用CGLIB实现。</p>
</li>
<li><p>CGLIB是一个强大的高性能的代码生成包，它可以在运行期扩展Java类与实现Java接口。它广泛的被许多AOP的框架使用，例如Spring AOP和dynaop，为他们提供方法的interception。</p>
</li>
<li><p>CGLIB包的底层是通过使用一个小而快的字节码处理框架ASM，来转换字节码并生成新的类。不鼓励直接使用ASM，因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉。</p>
</li>
</ul>
<h4 id="3-4-2-1-直接编写测试类"><a href="#3-4-2-1-直接编写测试类" class="headerlink" title="3.4.2.1 直接编写测试类"></a>3.4.2.1 直接编写测试类</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.lina.cglibproxy;</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">NBAService</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">add</span><span class="params">(String name,<span class="type">int</span> id)</span>&#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;NBAService---- add----&quot;</span>);</span><br><span class="line">        <span class="keyword">return</span> id;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">        <span class="comment">//目标对象:没有接口</span></span><br><span class="line">        NBAService nbaService=<span class="keyword">new</span> <span class="title class_">NBAService</span>();</span><br><span class="line">        <span class="comment">//创建代理对象：选择cglib动态代理</span></span><br><span class="line">        NBAService proxyService= (NBAService) Enhancer.create(nbaService.getClass(),</span><br><span class="line">                <span class="keyword">new</span> <span class="title class_">MethodInterceptor</span>() &#123;<span class="comment">//回调函数编写代理规则</span></span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="keyword">public</span> Object <span class="title function_">intercept</span><span class="params">(Object o, Method method, Object[] objects, MethodProxy methodProxy)</span> <span class="keyword">throws</span> Throwable &#123;</span><br><span class="line">                <span class="keyword">try</span> &#123;</span><br><span class="line">                    System.out.println(<span class="string">&quot;开始事务&quot;</span>);</span><br><span class="line">                    <span class="type">Object</span> <span class="variable">invoke</span> <span class="operator">=</span> methodProxy.invokeSuper(o, objects);<span class="comment">//核心</span></span><br><span class="line">                    System.out.println(<span class="string">&quot;提交事务&quot;</span>);</span><br><span class="line">                    <span class="keyword">return</span> invoke;</span><br><span class="line">                &#125;<span class="keyword">catch</span> (Exception e)&#123;</span><br><span class="line">                    System.out.println(<span class="string">&quot;事务回滚&quot;</span>);</span><br><span class="line">                    <span class="keyword">throw</span> e;</span><br><span class="line">                &#125;<span class="keyword">finally</span> &#123;</span><br><span class="line">                    System.out.println(<span class="string">&quot;finally------------&quot;</span>);</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;);</span><br><span class="line">        <span class="comment">//代理对象干活</span></span><br><span class="line">       <span class="type">int</span> res=proxyService.add(<span class="string">&quot;huren&quot;</span>,<span class="number">1001</span>);</span><br><span class="line">        System.out.println(res);</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>

<h4 id="3-4-2-2-结构化设计方式"><a href="#3-4-2-2-结构化设计方式" class="headerlink" title="3.4.2.2 结构化设计方式"></a>3.4.2.2 结构化设计方式</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.lina.cglibproxy;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.lina.aop.AOP;</span><br><span class="line"><span class="keyword">import</span> net.sf.cglib.proxy.Enhancer;</span><br><span class="line"><span class="keyword">import</span> net.sf.cglib.proxy.MethodInterceptor;</span><br><span class="line"><span class="keyword">import</span> net.sf.cglib.proxy.MethodProxy;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.Method;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">CglibProxyFactory</span> &#123;</span><br><span class="line">    <span class="comment">//目标对象</span></span><br><span class="line">    <span class="keyword">private</span> NBAService nbaService;<span class="comment">//没有实现接口的</span></span><br><span class="line">    <span class="comment">//切面</span></span><br><span class="line">    <span class="keyword">private</span> AOP aop;<span class="comment">//切面</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 创建代理对象</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> nbaService</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> aop</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> Object <span class="title function_">getProxyInstance</span><span class="params">(NBAService nbaService,AOP aop)</span>&#123;</span><br><span class="line">       <span class="keyword">return</span>  Enhancer.create(nbaService.getClass(),</span><br><span class="line">                <span class="keyword">new</span> <span class="title class_">MethodInterceptor</span>() &#123;</span><br><span class="line">                    <span class="meta">@Override</span></span><br><span class="line">                    <span class="keyword">public</span> Object <span class="title function_">intercept</span><span class="params">(Object o, Method method, Object[] objects, MethodProxy methodProxy)</span> <span class="keyword">throws</span> Throwable &#123;</span><br><span class="line">                        <span class="keyword">try</span> &#123;</span><br><span class="line">                            aop.before();</span><br><span class="line">                            <span class="type">Object</span> <span class="variable">o1</span> <span class="operator">=</span> methodProxy.invokeSuper(o, objects);</span><br><span class="line">                            aop.after();</span><br><span class="line">                            <span class="keyword">return</span> o1;</span><br><span class="line">                        &#125;<span class="keyword">catch</span> (Exception e)&#123;</span><br><span class="line">                            aop.exception();</span><br><span class="line">                            <span class="keyword">throw</span>  e;</span><br><span class="line">                        &#125;                        <span class="keyword">finally</span> &#123;</span><br><span class="line">                            System.out.println(<span class="string">&quot;finally-----------&quot;</span>);</span><br><span class="line">                        &#125;</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">        <span class="comment">//目标对象:没有接口</span></span><br><span class="line">        NBAService nbaService=<span class="keyword">new</span> <span class="title class_">NBAService</span>();</span><br><span class="line">        <span class="comment">//创建切面</span></span><br><span class="line">        AOP tranAop=<span class="keyword">new</span> <span class="title class_">TranAOP</span>();</span><br><span class="line">        <span class="comment">//创建代理对象：选择cglib动态代理</span></span><br><span class="line">        <span class="type">NBAService</span> <span class="variable">proxyInstance</span> <span class="operator">=</span> (NBAService) <span class="keyword">new</span> <span class="title class_">CglibProxyFactory</span>().getProxyInstance(nbaService, tranAop);</span><br><span class="line">        <span class="type">int</span> res=proxyInstance.add(<span class="string">&quot;huren&quot;</span>,<span class="number">1001</span>);</span><br><span class="line">        System.out.println(res);</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>

<h2 id="3-5-SpringAOP"><a href="#3-5-SpringAOP" class="headerlink" title="3.5 SpringAOP"></a>3.5 SpringAOP</h2><h3 id="3-5-1-Spring-AOP相关概念"><a href="#3-5-1-Spring-AOP相关概念" class="headerlink" title="3.5.1 Spring AOP相关概念"></a>3.5.1 Spring AOP相关概念</h3><p>Spring的AOP实现底层就是对上面的动态代理的代码进行了封装，封装后我们只需要对需要关注的部分进行代码编写，并通过配置的方式完成指定目标的方法增强。</p>
<p>我们先来介绍AOP的相关术语：</p>
<ul>
<li><h4 id="Target-目标对象"><a href="#Target-目标对象" class="headerlink" title="Target(目标对象)"></a>Target(目标对象)</h4></li>
</ul>
<p>要被增强的对象，一般是业务逻辑类的对象。–TeamService</p>
<ul>
<li><h4 id="Proxy（代理）"><a href="#Proxy（代理）" class="headerlink" title="Proxy（代理）"></a>Proxy（代理）</h4></li>
</ul>
<p> 一个类被 AOP 织入增强后，就产生一个结果代理类。 –ProxyTeamService–动态生成</p>
<ul>
<li><h4 id="Aspect-切面"><a href="#Aspect-切面" class="headerlink" title="Aspect(切面)"></a>Aspect(切面)</h4></li>
</ul>
<p> 表示增强的功能，就是一些代码完成的某个功能，非业务功能。是切入点和通知的结合。–服务性代码：日志 权限 事务</p>
<ul>
<li><h4 id="Joinpoint-连接点"><a href="#Joinpoint-连接点" class="headerlink" title="Joinpoint(连接点)"></a>Joinpoint(连接点)</h4></li>
</ul>
<p> 所谓连接点是指那些被拦截到的点。在Spring中,这些点指的是方法（一般是类中的业务方法）,因为Spring只支持方法类型的连接点。 –add()</p>
<ul>
<li><h4 id="Pointcut-切入点"><a href="#Pointcut-切入点" class="headerlink" title="Pointcut(切入点)"></a>Pointcut(切入点)</h4></li>
</ul>
<p>切入点指声明的一个或多个连接点的集合。通过切入点指定一组方法。</p>
<p>被标记为 final 的方法是不能作为连接点与切入点的。因为最终的是不能被修改的，不能被增强的。 </p>
<ul>
<li><h4 id="Advice-通知-增强"><a href="#Advice-通知-增强" class="headerlink" title="Advice(通知&#x2F;增强)"></a>Advice(通知&#x2F;增强)</h4>所谓通知是指拦截到 Joinpoint 之后所要做的事情就是通知。通知定义了增强代码切入到目标代码的时间点，是目标方法执行之前执行，还是之后执行等。通知类型不同，切入时间不同。<br>通知的类型：前置通知,后置通知,异常通知,最终通知,环绕通知。</li>
</ul>
<p>切入点定义切入的位置，通知定义切入的时间。</p>
<ul>
<li><h4 id="Weaving-织入"><a href="#Weaving-织入" class="headerlink" title="Weaving(织入)."></a>Weaving(织入).</h4></li>
</ul>
<p>是指把增强应用到目标对象来创建新的代理对象的过程。 spring 采用动态代理织入，而 AspectJ 采用编译期织入和类装载期织入。 </p>
<blockquote>
<p>切面的三个关键因素：</p>
<p>1、切面的功能–切面能干啥</p>
<p>2、切面的执行位置–使用Pointcut表示切面执行的位置</p>
<p>3、切面的执行时间–使用Advice表示时间，在目标方法之前还是之后执行。</p>
</blockquote>
<h3 id="3-5-2-AspectJ-对-AOP-的实现"><a href="#3-5-2-AspectJ-对-AOP-的实现" class="headerlink" title="3.5.2 AspectJ 对 AOP 的实现"></a>3.5.2 <strong>AspectJ</strong> <strong>对</strong> <strong>AOP</strong> 的实现</h3><p>对于 AOP 这种编程思想，很多框架都进行了实现。Spring 就是其中之一，可以完成面向切面编程。AspectJ 也实现了 AOP 的功能，且其实现方式更为简捷而且还支持注解式开发。所以，Spring 又将 AspectJ 的对于 AOP 的实现也引入到了自己的框架中。</p>
<p>在 Spring 中使用 AOP 开发时，一般使用 AspectJ 的实现方式</p>
<blockquote>
<p>AspectJ 是一个优秀面向切面的框架，它扩展了 Java 语言，提供了强大的切面实现。</p>
</blockquote>
<h4 id="3-5-2-1-AspectJ的通知类型"><a href="#3-5-2-1-AspectJ的通知类型" class="headerlink" title="3.5.2 .1 AspectJ的通知类型"></a>3.5.2 .1 AspectJ的通知类型</h4><p>AspectJ 中常用的通知有5种类型：</p>
<ol>
<li>前置通知</li>
<li>后置通知</li>
<li>环绕通知</li>
<li>异常通知</li>
<li>最终通知</li>
</ol>
<h4 id="3-5-2-2-AspectJ的切入点表达式"><a href="#3-5-2-2-AspectJ的切入点表达式" class="headerlink" title="3.5.2.2 AspectJ的切入点表达式"></a>3.5.2.2 AspectJ的切入点表达式</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">AspectJ 定义了专门的表达式用于指定切入点。</span><br><span class="line">表达式的原型如下：</span><br><span class="line">execution(modifiers-pattern? ret-type-pattern </span><br><span class="line">declaring-type-pattern?name-pattern(param-pattern)</span><br><span class="line"> throws-pattern?)</span><br><span class="line"> 说明：</span><br><span class="line"> 	modifiers-pattern  访问权限类型</span><br><span class="line">	ret-type-pattern  返回值类型</span><br><span class="line">	declaring-type-pattern 包名类名</span><br><span class="line">	name-pattern(param-pattern) 方法名(参数类型和参数个数)</span><br><span class="line">	throws-pattern 抛出异常类型</span><br><span class="line">	？表示可选的部分</span><br></pre></td></tr></table></figure>

<p>以上表达式共 4 个部分。<br>    execution(访问权限    <font color=red>方法返回值    方法声明(参数)</font>     异常类型)</p>
<p>切入点表达式要匹配的对象就是目标方法的方法名。所以，execution 表达式中就是方法的签名。</p>
<p>PS:表达式中黑色文字表示可省略部分，各部分间用空格分开。在其中可以使用以下符号：</p>
<table>
<thead>
<tr>
<th>符号</th>
<th>意义</th>
</tr>
</thead>
<tbody><tr>
<td>*</td>
<td>0-多个任意字符</td>
</tr>
<tr>
<td>..</td>
<td>用在方法参数中，表示任意个参数；用在包名后，表示当前及其子包路径</td>
</tr>
<tr>
<td>+</td>
<td>用在类名后，表示当前及其子类；用在接口后，表示当前接口及其实现类</td>
</tr>
</tbody></table>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">    示例：</span><br><span class="line">execution(* com.lina.service.*.*(..)) </span><br><span class="line">指定切入点为：定义在 service 包里的任意类的任意方法。</span><br><span class="line"></span><br><span class="line">execution(* com.lina.service..*.*(..))</span><br><span class="line">指定切入点为：定义在 service 包或者子包里的任意类的任意方法。“..”出现在类名中时，后面必须跟“*”，表示包、子包下的所有类。</span><br><span class="line"></span><br><span class="line">execution(* com.lina.service.IUserService+.*(..)) </span><br><span class="line">指定切入点为：IUserService 若为接口，则为接口中的任意方法及其所有实现类中的任意方法；若为类，则为该类及其子类中的任意方法。</span><br></pre></td></tr></table></figure>

<h3 id="3-5-3-注解方式实现AOP"><a href="#3-5-3-注解方式实现AOP" class="headerlink" title="3.5.3 注解方式实现AOP"></a>3.5.3 注解方式实现AOP</h3><p>开发阶段：关注核心业务和AOP代码</p>
<p>运行阶段：Spring框架会在运行的时候将核心业务和AOP代码通过动态代理的方式编织在一起</p>
<p>代理方式的选择：是否实现了接口：有接口就选择JDK动态代理；没有就选择CGLIB动态代理。</p>
<p>1、创建项目引入依赖</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependencies</span>&gt;</span></span><br><span class="line">        <span class="comment">&lt;!--spring 核心依赖--&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-context<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">version</span>&gt;</span>5.2.13.RELEASE<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-aspects<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">version</span>&gt;</span>5.2.13.RELEASE<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line">        <span class="comment">&lt;!--测试依赖--&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>junit<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>junit<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">version</span>&gt;</span>4.12<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">scope</span>&gt;</span>test<span class="tag">&lt;/<span class="name">scope</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">dependencies</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">build</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">plugins</span>&gt;</span></span><br><span class="line">            <span class="comment">&lt;!--编译插件--&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">plugin</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.apache.maven.plugins<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>maven-compiler-plugin<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">version</span>&gt;</span>3.8.0<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">configuration</span>&gt;</span></span><br><span class="line">                    <span class="tag">&lt;<span class="name">source</span>&gt;</span>1.8<span class="tag">&lt;/<span class="name">source</span>&gt;</span></span><br><span class="line">                    <span class="tag">&lt;<span class="name">target</span>&gt;</span>1.8<span class="tag">&lt;/<span class="name">target</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;/<span class="name">configuration</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;/<span class="name">plugin</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">plugins</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">build</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>2、创建spring配置文件引入约束</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?xml version=<span class="string">&quot;1.0&quot;</span> encoding=<span class="string">&quot;UTF-8&quot;</span>?&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">beans</span> <span class="attr">xmlns</span>=<span class="string">&quot;http://www.springframework.org/schema/beans&quot;</span></span></span><br><span class="line"><span class="tag">       <span class="attr">xmlns:xsi</span>=<span class="string">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span></span></span><br><span class="line"><span class="tag">       <span class="attr">xmlns:aop</span>=<span class="string">&quot;http://www.springframework.org/schema/aop&quot;</span></span></span><br><span class="line"><span class="tag">       <span class="attr">xmlns:context</span>=<span class="string">&quot;http://www.springframework.org/schema/context&quot;</span></span></span><br><span class="line"><span class="tag">       <span class="attr">xsi:schemaLocation</span>=<span class="string">&quot;http://www.springframework.org/schema/beans </span></span></span><br><span class="line"><span class="string"><span class="tag">                           http://www.springframework.org/schema/beans/spring-beans.xsd</span></span></span><br><span class="line"><span class="string"><span class="tag">        http://www.springframework.org/schema/aop</span></span></span><br><span class="line"><span class="string"><span class="tag">        http://www.springframework.org/schema/aop/spring-aop.xsd</span></span></span><br><span class="line"><span class="string"><span class="tag">        http://www.springframework.org/schema/context</span></span></span><br><span class="line"><span class="string"><span class="tag">        http://www.springframework.org/schema/context/spring-context.xsd&quot;</span>&gt;</span></span><br><span class="line">    <span class="comment">&lt;!--在beans标签中 引入AOP和context约束--&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">beans</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>3、创建核心业务类</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">interface</span> <span class="title class_">IService</span> &#123;</span><br><span class="line">    <span class="keyword">void</span> <span class="title function_">add</span><span class="params">(<span class="type">int</span> id,String name)</span>;</span><br><span class="line">    <span class="type">boolean</span> <span class="title function_">update</span><span class="params">(<span class="type">int</span> num)</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.lina.service;</span><br><span class="line"><span class="keyword">import</span> org.springframework.stereotype.Service;</span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 核心业务类</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@Service</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">TeamService</span> <span class="keyword">implements</span> <span class="title class_">IService</span>&#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">add</span><span class="params">(<span class="type">int</span> id, String name)</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;TeamService---- add----&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">update</span><span class="params">(<span class="type">int</span> num)</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;TeamService---- update----&quot;</span>);</span><br><span class="line">        <span class="comment">//int res=10/0;</span></span><br><span class="line">        <span class="keyword">if</span>(num&gt;<span class="number">666</span>)&#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.lina.service;</span><br><span class="line"><span class="keyword">import</span> org.springframework.stereotype.Service;</span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 核心业务类</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@Service(&quot;nbaService&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">NBAService</span> <span class="keyword">implements</span> <span class="title class_">IService</span>&#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">add</span><span class="params">(<span class="type">int</span> id, String name)</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;NBAService---- add----&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">update</span><span class="params">(<span class="type">int</span> num)</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;NBAService---- update----&quot;</span>);</span><br><span class="line">        <span class="comment">//int res=10/0;</span></span><br><span class="line">        <span class="keyword">if</span>(num&gt;<span class="number">666</span>)&#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>4、定义切面类</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.lina.aop;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.aspectj.lang.JoinPoint;</span><br><span class="line"><span class="keyword">import</span> org.aspectj.lang.ProceedingJoinPoint;</span><br><span class="line"><span class="keyword">import</span> org.aspectj.lang.Signature;</span><br><span class="line"><span class="keyword">import</span> org.aspectj.lang.annotation.*;</span><br><span class="line"><span class="keyword">import</span> org.springframework.stereotype.Component;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 切面类</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@Component</span> <span class="comment">//切面对象的创建权限依然交给spring容器</span></span><br><span class="line"><span class="meta">@Aspect</span> <span class="comment">//aspectj   框架的注解  标识当前类是一个切面类</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">MyAspect</span>&#123;</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 当较多的通知增强方法使用相同的 execution 切入点表达式时，编写、维护均较为麻烦。</span></span><br><span class="line"><span class="comment">     * AspectJ 提供了<span class="doctag">@Pointcut</span> 注解，用于定义 execution 切入点表达式。</span></span><br><span class="line"><span class="comment">     * 其用法是，将<span class="doctag">@Pointcut</span> 注解在一个方法之上，以后所有的 execution 的 value 属性值均</span></span><br><span class="line"><span class="comment">     * 可使用该方法名作为切入点。代表的就是<span class="doctag">@Pointcut</span> 定义的切入点。</span></span><br><span class="line"><span class="comment">     * 这个使用<span class="doctag">@Pointcut</span> 注解方法一般使用 private 的标识方法，即没有实际作用的方法。</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="meta">@Pointcut(&quot;execution(* com.lina.service..*.*(..))&quot;)</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">void</span> <span class="title function_">pointCut</span><span class="params">()</span>&#123;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="meta">@Pointcut(&quot;execution(* com.lina.service..*.add*(..))&quot;)</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">void</span> <span class="title function_">pointCut2</span><span class="params">()</span>&#123;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 声明前置通知</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> jp</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="meta">@Before(&quot;pointCut()&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">before</span><span class="params">(JoinPoint jp)</span>&#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;前置通知：在目标方法执行之前被调用的通知&quot;</span>);</span><br><span class="line">        <span class="type">String</span> <span class="variable">name</span> <span class="operator">=</span> jp.getSignature().getName();</span><br><span class="line">        System.out.println(<span class="string">&quot;拦截的方法名称：&quot;</span>+name);</span><br><span class="line">        Object[] args = jp.getArgs();</span><br><span class="line">        System.out.println(<span class="string">&quot;方法的参数格式：&quot;</span>+args.length);</span><br><span class="line">        System.out.println(<span class="string">&quot;方法参数列表：&quot;</span>);</span><br><span class="line">        <span class="keyword">for</span> (Object arg : args) &#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;\t&quot;</span>+arg);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * AfterReturning 注解声明后置通知</span></span><br><span class="line"><span class="comment">     *  value： 表示切入点表达式</span></span><br><span class="line"><span class="comment">     *  returning 属性表示 返回的结果，如果需要的话可以在后置通知的方法中修改结果</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="meta">@AfterReturning(value = &quot;pointCut2()&quot;,returning = &quot;result&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> Object <span class="title function_">afterReturn</span><span class="params">(Object result)</span>&#123;</span><br><span class="line">        <span class="keyword">if</span>(result!=<span class="literal">null</span>)&#123;</span><br><span class="line">           <span class="type">boolean</span> res=(<span class="type">boolean</span>)result;</span><br><span class="line">           <span class="keyword">if</span>(res)&#123;</span><br><span class="line">               result=<span class="literal">false</span>;</span><br><span class="line">           &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        System.out.println(<span class="string">&quot;后置通知：在目标方法执行之后被调用的通知,result=&quot;</span>+result);</span><br><span class="line">        <span class="keyword">return</span> result;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * Around 注解声明环绕通知</span></span><br><span class="line"><span class="comment">     *   ProceedingJoinPoint 中的proceed方法表示目标方法被执行</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="meta">@Around(value = &quot;pointCut()&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> Object <span class="title function_">around</span><span class="params">(ProceedingJoinPoint pjp)</span> <span class="keyword">throws</span> Throwable &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;环绕方法---目标方法的执行之前&quot;</span>);</span><br><span class="line">        <span class="type">Object</span> <span class="variable">proceed</span> <span class="operator">=</span> pjp.proceed();</span><br><span class="line">        System.out.println(<span class="string">&quot;环绕方法---目标方法的执行之后&quot;</span>);</span><br><span class="line">        <span class="keyword">return</span> proceed;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * AfterThrowing 注解声明异常通知方法</span></span><br><span class="line"><span class="comment">     *  value： 表示切入点表达式</span></span><br><span class="line"><span class="comment">     *  returning 属性表示 返回的结果，如果需要的话可以在后置通知的方法中修改结果</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="meta">@AfterThrowing(value = &quot;pointCut()&quot;,throwing = &quot;ex&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">exception</span><span class="params">(JoinPoint jp,Throwable ex)</span>&#123;</span><br><span class="line">        <span class="comment">//一般会把异常发生的时间、位置、原有都记录下来</span></span><br><span class="line">        System.out.println(<span class="string">&quot;异常通知：在目标方法执行出现异常的时候才会别调用的通知，否则不执行&quot;</span>);</span><br><span class="line">        System.out.println(jp.getSignature()+<span class="string">&quot;方法出现异常，异常信息是：&quot;</span>+ex.getMessage());</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * After 注解声明为最终通知</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="meta">@After( &quot;pointCut()&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">myFinally</span><span class="params">()</span>&#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;最终通知：无论是否出现异常都是最后被调用的通知&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p>5、业务类和切面类添加注解</p>
<p><img src="/img%5Cimage-20210319163551308.png" class="lazyload" data-srcset="/img%5Cimage-20210319163551308.png" srcset="" alt="image-20210319163551308"><img src="/img%5Cimage-20210319163615783.png" class="lazyload" data-srcset="/img%5Cimage-20210319163615783.png" srcset="" alt="image-20210319163615783"><img src="/img%5Cimage-20210319163634664.png" class="lazyload" data-srcset="/img%5Cimage-20210319163634664.png" srcset="" alt="image-20210319163634664"></p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">在定义好切面 Aspect 后，需要通知 Spring 容器，让容器生成“目标类+ 切面”的代理对象。这个代理是由容器自动生成的。只需要在 Spring 配置文件中注册一个基于 aspectj 的自动代理生成器，其就会自动扫描到@Aspect 注解，并按通知类型与切入点，将其织入，并生成代理。</span><br></pre></td></tr></table></figure>

<p>5、spring.xml配置文件中开启包扫描和 注册aspectj的自动代理</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">    <span class="comment">&lt;!--包扫描--&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">context:component-scan</span> <span class="attr">base-package</span>=<span class="string">&quot;com.lina.service,com.lina.aop&quot;</span>/&gt;</span></span><br><span class="line">    <span class="comment">&lt;!--开启注解AOP的使用--&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">aop:aspectj-autoproxy</span> <span class="attr">proxy-target-class</span>=<span class="string">&quot;true&quot;</span>/&gt;</span></span><br><span class="line"> <span class="comment">&lt;!--aop:aspectj-autoproxy的底层是由 AnnotationAwareAspectJAutoProxyCreator 实现的,是基于 AspectJ 的注解适配自动代理生成器。</span></span><br><span class="line"><span class="comment">其工作原理是，aop:aspectj-autoproxy通过扫描找到@Aspect 定义的切面类，再由切面类根据切入点找到目标类的目标方法，再由通知类型找到切入的时间点。--&gt;</span></span><br></pre></td></tr></table></figure>

<p>6.测试类：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.lina.test;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.lina.service.NBAService;</span><br><span class="line"><span class="keyword">import</span> com.lina.service.TeamService;</span><br><span class="line"><span class="keyword">import</span> org.junit.Test;</span><br><span class="line"><span class="keyword">import</span> org.springframework.context.ApplicationContext;</span><br><span class="line"><span class="keyword">import</span> org.springframework.context.support.ClassPathXmlApplicationContext;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Test01</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Test</span></span><br><span class="line">    <span class="keyword">public</span>  <span class="keyword">void</span> <span class="title function_">test01</span><span class="params">()</span>&#123;</span><br><span class="line">        ApplicationContext ac=<span class="keyword">new</span> <span class="title class_">ClassPathXmlApplicationContext</span>(<span class="string">&quot;spring.xml&quot;</span>);</span><br><span class="line">        <span class="type">TeamService</span> <span class="variable">teamService</span> <span class="operator">=</span> (TeamService) ac.getBean(<span class="string">&quot;teamService&quot;</span>);</span><br><span class="line">        teamService.add(<span class="number">1001</span>,<span class="string">&quot;湖人队&quot;</span>);</span><br><span class="line">        System.out.println(<span class="string">&quot;--------------------------&quot;</span>);</span><br><span class="line">        <span class="type">boolean</span> <span class="variable">update</span> <span class="operator">=</span> teamService.update(<span class="number">888</span>);</span><br><span class="line">        System.out.println(<span class="string">&quot;update 结果=&quot;</span>+update);</span><br><span class="line">        System.out.println(<span class="string">&quot;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~&quot;</span>);</span><br><span class="line">        <span class="type">NBAService</span> <span class="variable">nbaService</span> <span class="operator">=</span> (NBAService) ac.getBean(<span class="string">&quot;nbaService&quot;</span>);</span><br><span class="line">        nbaService.add(<span class="number">1002</span>,<span class="string">&quot;热火&quot;</span>);</span><br><span class="line">        System.out.println(<span class="string">&quot;--------------------------&quot;</span>);</span><br><span class="line">        <span class="type">boolean</span> <span class="variable">update2</span> <span class="operator">=</span> teamService.update(<span class="number">888</span>);</span><br><span class="line">        System.out.println(<span class="string">&quot;update 结果=&quot;</span>+update2);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<h3 id="3-5-4-XML方式实现AOP"><a href="#3-5-4-XML方式实现AOP" class="headerlink" title="3.5.4 XML方式实现AOP"></a>3.5.4 XML方式实现AOP</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.lina.aop;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.aspectj.lang.JoinPoint;</span><br><span class="line"><span class="keyword">import</span> org.aspectj.lang.ProceedingJoinPoint;</span><br><span class="line"><span class="keyword">import</span> org.aspectj.lang.annotation.*;</span><br><span class="line"><span class="keyword">import</span> org.springframework.stereotype.Component;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 切面类</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@Component</span> <span class="comment">//切面对象的创建权限依然交给spring容器</span></span><br><span class="line"><span class="meta">@Aspect</span> <span class="comment">//aspectj   框架的注解  标识当前类是一个切面类</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">MyAOP</span> &#123;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">before</span><span class="params">(JoinPoint jp)</span>&#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;AOP前置通知：在目标方法执行之前被调用的通知&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">afterReturn</span><span class="params">(Object result)</span>&#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;AOP后置通知：在目标方法执行之后被调用的通知,result=&quot;</span>+result);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> Object <span class="title function_">around</span><span class="params">(ProceedingJoinPoint pjp)</span> <span class="keyword">throws</span> Throwable &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;AOP环绕方法---目标方法的执行之前&quot;</span>);</span><br><span class="line">        <span class="type">Object</span> <span class="variable">proceed</span> <span class="operator">=</span> pjp.proceed();</span><br><span class="line">        System.out.println(<span class="string">&quot;AOP环绕方法---目标方法的执行之后&quot;</span>);</span><br><span class="line">        <span class="keyword">return</span> proceed;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">exception</span><span class="params">(JoinPoint jp,Throwable ex)</span>&#123;</span><br><span class="line">        <span class="comment">//一般会把异常发生的时间、位置、原有都记录下来</span></span><br><span class="line">        System.out.println(<span class="string">&quot;AOP异常通知：在目标方法执行出现异常的时候才会别调用的通知，否则不执行&quot;</span>);</span><br><span class="line">        System.out.println(jp.getSignature()+<span class="string">&quot;方法出现异常，异常信息是：&quot;</span>+ex.getMessage());</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">myFinally</span><span class="params">()</span>&#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;AOP最终通知：无论是否出现异常都是最后被调用的通知&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">aop:config</span>&gt;</span></span><br><span class="line">    <span class="comment">&lt;!--声明切入点的表达式,可以声明多个--&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">aop:pointcut</span> <span class="attr">id</span>=<span class="string">&quot;pt1&quot;</span> <span class="attr">expression</span>=<span class="string">&quot;execution(* com.lina.service..*.add*(..))&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">aop:pointcut</span> <span class="attr">id</span>=<span class="string">&quot;pt2&quot;</span> <span class="attr">expression</span>=<span class="string">&quot;execution(* com.lina.service..*.update*(..))&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">aop:pointcut</span> <span class="attr">id</span>=<span class="string">&quot;pt3&quot;</span> <span class="attr">expression</span>=<span class="string">&quot;execution(* com.lina.service..*.del*(..))&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">aop:pointcut</span> <span class="attr">id</span>=<span class="string">&quot;pt4&quot;</span> <span class="attr">expression</span>=<span class="string">&quot;execution(* com.lina.service..*.insert*(..))&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">aop:aspect</span> <span class="attr">ref</span>=<span class="string">&quot;myAOP&quot;</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">aop:before</span> <span class="attr">method</span>=<span class="string">&quot;before&quot;</span> <span class="attr">pointcut</span>=<span class="string">&quot;execution(* com.lina.service..*.*(..))&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">aop:before</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">aop:after-returning</span> <span class="attr">method</span>=<span class="string">&quot;afterReturn&quot;</span> <span class="attr">pointcut-ref</span>=<span class="string">&quot;pt2&quot;</span> <span class="attr">returning</span>=<span class="string">&quot;result&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">aop:after-returning</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">aop:after-throwing</span> <span class="attr">method</span>=<span class="string">&quot;exception&quot;</span> <span class="attr">pointcut-ref</span>=<span class="string">&quot;pt1&quot;</span> <span class="attr">throwing</span>=<span class="string">&quot;ex&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">aop:after-throwing</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">aop:after</span> <span class="attr">method</span>=<span class="string">&quot;myFinally&quot;</span> <span class="attr">pointcut-ref</span>=<span class="string">&quot;pt1&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">aop:after</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">aop:around</span> <span class="attr">method</span>=<span class="string">&quot;around&quot;</span> <span class="attr">pointcut-ref</span>=<span class="string">&quot;pt2&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">aop:around</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">aop:aspect</span>&gt;</span></span><br></pre></td></tr></table></figure>

<h1 id="4、Spring整合JDBC"><a href="#4、Spring整合JDBC" class="headerlink" title="4、Spring整合JDBC"></a>4、Spring整合JDBC</h1><h2 id="4-1-使用spring-jdbc操作数据库"><a href="#4-1-使用spring-jdbc操作数据库" class="headerlink" title="4.1 使用spring-jdbc操作数据库"></a>4.1 使用spring-jdbc操作数据库</h2><p>主要内容:学习使用JdbcTemplate API和 如何使用Spring管理 JdbcTemplate</p>
<p>1、创建项目引入依赖</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependencies</span>&gt;</span></span><br><span class="line">        <span class="comment">&lt;!--spring 核心依赖--&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-context<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">version</span>&gt;</span>5.2.13.RELEASE<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-jdbc<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">version</span>&gt;</span>5.2.13.RELEASE<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>mysql<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>mysql-connector-java<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">version</span>&gt;</span>8.0.23<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>com.mchange<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>c3p0<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">version</span>&gt;</span>0.9.5.2<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line">        <span class="comment">&lt;!--测试依赖--&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>junit<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>junit<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">version</span>&gt;</span>4.12<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">scope</span>&gt;</span>test<span class="tag">&lt;/<span class="name">scope</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">dependencies</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">build</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">plugins</span>&gt;</span></span><br><span class="line">            <span class="comment">&lt;!--编译插件--&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">plugin</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.apache.maven.plugins<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>maven-compiler-plugin<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">version</span>&gt;</span>3.8.0<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">configuration</span>&gt;</span></span><br><span class="line">                    <span class="tag">&lt;<span class="name">source</span>&gt;</span>1.8<span class="tag">&lt;/<span class="name">source</span>&gt;</span></span><br><span class="line">                    <span class="tag">&lt;<span class="name">target</span>&gt;</span>1.8<span class="tag">&lt;/<span class="name">target</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;/<span class="name">configuration</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;/<span class="name">plugin</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">plugins</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">build</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>2、测试连接</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.lina.test;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.mchange.v2.c3p0.ComboPooledDataSource;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.junit.Test;</span><br><span class="line"><span class="keyword">import</span> org.springframework.jdbc.core.JdbcTemplate;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.beans.PropertyVetoException;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Test01</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Test</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">test01</span><span class="params">()</span> <span class="keyword">throws</span> PropertyVetoException &#123;</span><br><span class="line">        <span class="comment">//创建数据源</span></span><br><span class="line">        ComboPooledDataSource dataSource=<span class="keyword">new</span> <span class="title class_">ComboPooledDataSource</span>();</span><br><span class="line">        dataSource.setDriverClass(<span class="string">&quot;com.mysql.cj.jdbc.Driver&quot;</span>);</span><br><span class="line">        dataSource.setJdbcUrl(<span class="string">&quot;jdbc:mysql://127.0.0.1:3306/springJDBC?serverTimezone=Asia/Shanghai&amp;characterEncoding=utf8&amp;useUnicode=true&amp;useSSL=false&quot;</span>);</span><br><span class="line">        dataSource.setUser(<span class="string">&quot;root&quot;</span>);</span><br><span class="line">        dataSource.setPassword(<span class="string">&quot;root&quot;</span>);</span><br><span class="line">        <span class="comment">//使用JDBCTemplete</span></span><br><span class="line">        JdbcTemplate template=<span class="keyword">new</span> <span class="title class_">JdbcTemplate</span>(dataSource);</span><br><span class="line">        String sql=<span class="string">&quot;insert into team(tname,location) value (?,?)&quot;</span>;</span><br><span class="line">        <span class="type">int</span> <span class="variable">update</span> <span class="operator">=</span> template.update(sql,<span class="string">&quot;勇士&quot;</span>,<span class="string">&quot;金州&quot;</span>);</span><br><span class="line">        System.out.println(<span class="string">&quot;插入数据的结果：&quot;</span>+update);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<h2 id="4-2-Spring管理JdbcTemplate"><a href="#4-2-Spring管理JdbcTemplate" class="headerlink" title="4.2. Spring管理JdbcTemplate"></a>4.2. Spring管理JdbcTemplate</h2><p>spring整合jdbc的时候我们都是直接让我的dao继承Spring提供的JdbcDaoSupport类，该类中提供了JdbcTemplate模板可用。</p>
<p>示例 ：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.lina.dao;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.lina.pojo.Team;</span><br><span class="line"><span class="keyword">import</span> org.springframework.jdbc.core.RowMapper;</span><br><span class="line"><span class="keyword">import</span> org.springframework.jdbc.core.support.JdbcDaoSupport;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.sql.ResultSet;</span><br><span class="line"><span class="keyword">import</span> java.sql.SQLException;</span><br><span class="line"><span class="keyword">import</span> java.util.List;</span><br><span class="line"><span class="keyword">import</span> java.util.Map;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">TeamDao</span> <span class="keyword">extends</span> <span class="title class_">JdbcDaoSupport</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> Map&lt;String,Object&gt; <span class="title function_">getMany</span><span class="params">()</span>&#123;</span><br><span class="line">        String sql=<span class="string">&quot;select max(tid) as max,min(tid) as min from team&quot;</span>;</span><br><span class="line">        <span class="keyword">return</span> <span class="built_in">this</span>.getJdbcTemplate().queryForMap(sql);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">getCount</span><span class="params">()</span>&#123;</span><br><span class="line">        String sql=<span class="string">&quot;select count(tid) from team&quot;</span>;</span><br><span class="line">        <span class="comment">//如果查询的列只有唯一一列，queryForObject（sql语句,唯一列的数据类型）</span></span><br><span class="line">        <span class="keyword">return</span> <span class="built_in">this</span>.getJdbcTemplate().queryForObject(sql,Integer.class);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 自己封装处理结果的方法</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> resultSet</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">     * <span class="doctag">@throws</span> SQLException</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> Team <span class="title function_">handlResult</span><span class="params">(ResultSet resultSet)</span> <span class="keyword">throws</span> SQLException &#123;</span><br><span class="line">        Team team=<span class="keyword">new</span> <span class="title class_">Team</span>();</span><br><span class="line">        team.settId(resultSet.getInt(<span class="string">&quot;tid&quot;</span>));</span><br><span class="line">        team.settName(resultSet.getString(<span class="string">&quot;tname&quot;</span>));</span><br><span class="line">        team.setLocation(resultSet.getString(<span class="string">&quot;location&quot;</span>));</span><br><span class="line">        <span class="keyword">return</span> team;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> List&lt;Team&gt; <span class="title function_">findByAll</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="type">String</span> <span class="variable">sql</span> <span class="operator">=</span> <span class="string">&quot;select * from team&quot;</span>;</span><br><span class="line">        <span class="keyword">return</span> <span class="built_in">this</span>.getJdbcTemplate().query(sql, <span class="keyword">new</span> <span class="title class_">RowMapper</span>&lt;Team&gt;() &#123;</span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="keyword">public</span> Team <span class="title function_">mapRow</span><span class="params">(ResultSet resultSet, <span class="type">int</span> i)</span> <span class="keyword">throws</span> SQLException &#123;</span><br><span class="line">                <span class="comment">/*Team team=new Team();</span></span><br><span class="line"><span class="comment">                team.settId(resultSet.getInt(&quot;tid&quot;));</span></span><br><span class="line"><span class="comment">                team.settName(resultSet.getString(&quot;tname&quot;));</span></span><br><span class="line"><span class="comment">                team.setLocation(resultSet.getString(&quot;location&quot;));</span></span><br><span class="line"><span class="comment">                return team;*/</span></span><br><span class="line">                <span class="keyword">return</span> handlResult(resultSet);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> Team <span class="title function_">findById</span><span class="params">(<span class="type">int</span> id)</span>&#123;</span><br><span class="line">        String sql=<span class="string">&quot;select * from team where tid=?&quot;</span>;</span><br><span class="line">        <span class="keyword">return</span> <span class="built_in">this</span>.getJdbcTemplate().queryForObject(sql, <span class="keyword">new</span> <span class="title class_">Object</span>[]&#123;id&#125;, <span class="keyword">new</span> <span class="title class_">RowMapper</span>&lt;Team&gt;() &#123;</span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="keyword">public</span> Team <span class="title function_">mapRow</span><span class="params">(ResultSet resultSet, <span class="type">int</span> i)</span> <span class="keyword">throws</span> SQLException &#123;</span><br><span class="line">                <span class="comment">/*Team team=new Team();</span></span><br><span class="line"><span class="comment">                team.settId(resultSet.getInt(&quot;tid&quot;));</span></span><br><span class="line"><span class="comment">                team.settName(resultSet.getString(&quot;tname&quot;));</span></span><br><span class="line"><span class="comment">                team.setLocation(resultSet.getString(&quot;location&quot;));</span></span><br><span class="line"><span class="comment">                return team;*/</span></span><br><span class="line">                <span class="keyword">return</span> handlResult(resultSet);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">insert</span><span class="params">(Team team)</span>&#123;</span><br><span class="line">        String sql=<span class="string">&quot;INSERT INTO `springjdbc`.`team` ( `tname`, `location`) VALUES (?,?)&quot;</span>;</span><br><span class="line">        <span class="keyword">return</span> <span class="built_in">this</span>.getJdbcTemplate().update(sql,team.gettName(),team.getLocation());</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">update</span><span class="params">(Team team)</span>&#123;</span><br><span class="line">        String sql=<span class="string">&quot;UPDATE `springjdbc`.`team` SET `tname` = ?, `location` = ? WHERE `tid` = ?&quot;</span>;</span><br><span class="line">        <span class="keyword">return</span> <span class="built_in">this</span>.getJdbcTemplate().update(sql,team.gettName(),team.getLocation(),team.gettId());</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">del</span><span class="params">(<span class="type">int</span> id)</span>&#123;</span><br><span class="line">        String sql=<span class="string">&quot;delete from team where tid=?&quot;</span>;</span><br><span class="line">        <span class="keyword">return</span> <span class="built_in">this</span>.getJdbcTemplate().update(sql,id);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p>spring的配置文件application.xml中需要创建数据源和给TeamDao中的jdbcTemplate赋值</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?xml version=<span class="string">&quot;1.0&quot;</span> encoding=<span class="string">&quot;UTF-8&quot;</span>?&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">beans</span> <span class="attr">xmlns</span>=<span class="string">&quot;http://www.springframework.org/schema/beans&quot;</span></span></span><br><span class="line"><span class="tag">       <span class="attr">xmlns:xsi</span>=<span class="string">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span></span></span><br><span class="line"><span class="tag">       <span class="attr">xsi:schemaLocation</span>=<span class="string">&quot;http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd&quot;</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">&lt;!--创建数据源--&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;dataSource&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.mchange.v2.c3p0.ComboPooledDataSource&quot;</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;driverClass&quot;</span> <span class="attr">value</span>=<span class="string">&quot;com.mysql.cj.jdbc.Driver&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">property</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;jdbcUrl&quot;</span> <span class="attr">value</span>=<span class="string">&quot;jdbc:mysql://192.168.58.128:3306/springJDBC?serverTimezone=UTC<span class="symbol">&amp;amp;</span>characterEncoding=utf8<span class="symbol">&amp;amp;</span>useUnicode=true<span class="symbol">&amp;amp;</span>useSSL=false&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">property</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;user&quot;</span> <span class="attr">value</span>=<span class="string">&quot;root&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">property</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;password&quot;</span> <span class="attr">value</span>=<span class="string">&quot;root&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">property</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br><span class="line">    <span class="comment">&lt;!--创建JdbcTemplate--&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;jdbcTemplate&quot;</span> <span class="attr">class</span>=<span class="string">&quot;org.springframework.jdbc.core.JdbcTemplate&quot;</span>&gt;</span></span><br><span class="line">        <span class="comment">&lt;!--需要注入数据源--&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;dataSource&quot;</span> <span class="attr">ref</span>=<span class="string">&quot;dataSource&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">property</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;teamDao&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.lina.dao.TeamDao&quot;</span>&gt;</span></span><br><span class="line">        <span class="comment">&lt;!--需要JdbcTemplate--&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;jdbcTemplate&quot;</span> <span class="attr">ref</span>=<span class="string">&quot;jdbcTemplate&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">property</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">beans</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>测试：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.lina.test;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.lina.dao.TeamDao;</span><br><span class="line"><span class="keyword">import</span> com.lina.pojo.Team;</span><br><span class="line"><span class="keyword">import</span> com.mchange.v2.c3p0.ComboPooledDataSource;</span><br><span class="line"><span class="keyword">import</span> org.junit.Test;</span><br><span class="line"><span class="keyword">import</span> org.springframework.context.ApplicationContext;</span><br><span class="line"><span class="keyword">import</span> org.springframework.context.support.ClassPathXmlApplicationContext;</span><br><span class="line"><span class="keyword">import</span> org.springframework.jdbc.core.JdbcTemplate;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.beans.PropertyVetoException;</span><br><span class="line"><span class="keyword">import</span> java.util.List;</span><br><span class="line"><span class="keyword">import</span> java.util.Map;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Test01</span> &#123;</span><br><span class="line">    ApplicationContext ac=<span class="keyword">new</span> <span class="title class_">ClassPathXmlApplicationContext</span>(<span class="string">&quot;spring.xml&quot;</span>);</span><br><span class="line">    <span class="meta">@Test</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">testGetMany</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="type">TeamDao</span> <span class="variable">teamDao</span> <span class="operator">=</span> (TeamDao) ac.getBean(<span class="string">&quot;teamDao&quot;</span>);</span><br><span class="line">        Map&lt;String, Object&gt; many = teamDao.getMany();</span><br><span class="line">        <span class="keyword">for</span> (String s : many.keySet()) &#123;</span><br><span class="line">            System.out.println(s+<span class="string">&quot;-----&quot;</span>+many.get(s));</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="meta">@Test</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">testGetCount</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="type">TeamDao</span> <span class="variable">teamDao</span> <span class="operator">=</span> (TeamDao) ac.getBean(<span class="string">&quot;teamDao&quot;</span>);</span><br><span class="line">        <span class="type">int</span> <span class="variable">count</span> <span class="operator">=</span> teamDao.getCount();</span><br><span class="line">        System.out.println(<span class="string">&quot;count=&quot;</span>+count);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="meta">@Test</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">testFindAll</span><span class="params">()</span>&#123;</span><br><span class="line">        TeamDao teamDao= (TeamDao) ac.getBean(<span class="string">&quot;teamDao&quot;</span>);</span><br><span class="line">        List&lt;Team&gt; byAll = teamDao.findByAll();</span><br><span class="line">        <span class="keyword">for</span> (Team team : byAll) &#123;</span><br><span class="line">            System.out.println(team);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="meta">@Test</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">testFindById</span><span class="params">()</span>&#123;</span><br><span class="line">        TeamDao teamDao= (TeamDao) ac.getBean(<span class="string">&quot;teamDao&quot;</span>);</span><br><span class="line">        <span class="type">Team</span> <span class="variable">team</span> <span class="operator">=</span> teamDao.findById(<span class="number">1</span>);</span><br><span class="line">        System.out.println(team);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="meta">@Test</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">test04</span><span class="params">()</span>&#123;</span><br><span class="line"></span><br><span class="line">        TeamDao teamDao= (TeamDao) ac.getBean(<span class="string">&quot;teamDao&quot;</span>);</span><br><span class="line"></span><br><span class="line">        <span class="type">int</span> <span class="variable">insert</span> <span class="operator">=</span> teamDao.del(<span class="number">4</span>);</span><br><span class="line">        System.out.println(<span class="string">&quot;删除数据的结果是：&quot;</span>+insert);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="meta">@Test</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">test03</span><span class="params">()</span>&#123;</span><br><span class="line">        ApplicationContext ac=<span class="keyword">new</span> <span class="title class_">ClassPathXmlApplicationContext</span>(<span class="string">&quot;spring.xml&quot;</span>);</span><br><span class="line">        TeamDao teamDao= (TeamDao) ac.getBean(<span class="string">&quot;teamDao&quot;</span>);</span><br><span class="line">        Team team=<span class="keyword">new</span> <span class="title class_">Team</span>();</span><br><span class="line">        team.settId(<span class="number">2</span>);</span><br><span class="line">        team.settName(<span class="string">&quot;勇士&quot;</span>);</span><br><span class="line">        team.setLocation(<span class="string">&quot;金州&quot;</span>);</span><br><span class="line">        <span class="type">int</span> <span class="variable">insert</span> <span class="operator">=</span> teamDao.update(team);</span><br><span class="line">        System.out.println(<span class="string">&quot;修改数据的结果是：&quot;</span>+insert);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="meta">@Test</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">test02</span><span class="params">()</span>&#123;</span><br><span class="line">        ApplicationContext ac=<span class="keyword">new</span> <span class="title class_">ClassPathXmlApplicationContext</span>(<span class="string">&quot;spring.xml&quot;</span>);</span><br><span class="line">        TeamDao teamDao= (TeamDao) ac.getBean(<span class="string">&quot;teamDao&quot;</span>);</span><br><span class="line">        Team team=<span class="keyword">new</span> <span class="title class_">Team</span>();</span><br><span class="line">        team.settName(<span class="string">&quot;快船&quot;</span>);</span><br><span class="line">        team.setLocation(<span class="string">&quot;洛杉矶&quot;</span>);</span><br><span class="line">        <span class="type">int</span> <span class="variable">insert</span> <span class="operator">=</span> teamDao.insert(team);</span><br><span class="line">        System.out.println(<span class="string">&quot;插入数据的结果是：&quot;</span>+insert);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Test</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">test01</span><span class="params">()</span> <span class="keyword">throws</span> PropertyVetoException &#123;</span><br><span class="line">        <span class="comment">//创建数据源</span></span><br><span class="line">        ComboPooledDataSource dataSource=<span class="keyword">new</span> <span class="title class_">ComboPooledDataSource</span>();</span><br><span class="line">        dataSource.setDriverClass(<span class="string">&quot;com.mysql.cj.jdbc.Driver&quot;</span>);</span><br><span class="line">        dataSource.setJdbcUrl(<span class="string">&quot;jdbc:mysql://127.0.0.1:3306/springJDBC?serverTimezone=Asia/Shanghai&amp;characterEncoding=utf8&amp;useUnicode=true&amp;useSSL=false&quot;</span>);</span><br><span class="line">        dataSource.setUser(<span class="string">&quot;root&quot;</span>);</span><br><span class="line">        dataSource.setPassword(<span class="string">&quot;root&quot;</span>);</span><br><span class="line">        <span class="comment">//使用JdbcTemplate</span></span><br><span class="line">        JdbcTemplate template=<span class="keyword">new</span> <span class="title class_">JdbcTemplate</span>(dataSource);</span><br><span class="line">        String sql=<span class="string">&quot;INSERT INTO `springjdbc`.`team` ( `tname`, `location`) VALUES (?,?)&quot;</span>;</span><br><span class="line">        <span class="type">int</span> <span class="variable">update</span> <span class="operator">=</span> template.update(sql,<span class="string">&quot;勇士&quot;</span>,<span class="string">&quot;金州&quot;</span>);</span><br><span class="line">        System.out.println(<span class="string">&quot;插入数据的结果是：&quot;</span>+update);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<h1 id="5、Spring事务管理"><a href="#5、Spring事务管理" class="headerlink" title="5、Spring事务管理"></a>5、Spring事务管理</h1><p>事务原本是数据库中的概念，在jdbc中我们将事务放在了数据访问层。但在实际开发中，一般将事务提升到业务层，即 Service 层。这样做是为了能够使用事务的特性来管理具体的业务。</p>
<h2 id="5-1-Spring事务管理API"><a href="#5-1-Spring事务管理API" class="headerlink" title="5.1 Spring事务管理API"></a>5.1 Spring事务管理API</h2><p>Spring 的事务管理，主要用到两个事务相关的接口。</p>
<h3 id="5-1-1-事务管理器接口"><a href="#5-1-1-事务管理器接口" class="headerlink" title="5.1.1 事务管理器接口"></a>5.1.1 事务管理器接口</h3><p>事务管理器是 PlatformTransactionManager 接口对象。其主要用于完成事务的提交、回滚，及获取事务的状态信息。</p>
<p><img src="/img%5Cimage-20210317112608191.png" class="lazyload" data-srcset="/img%5Cimage-20210317112608191.png" srcset="" alt="image-20210317112608191"></p>
<p><strong>PlatformTransactionManager 接口常用的实现类</strong>：</p>
<p>DataSourceTransactionManager：使用 JDBC 或 MyBatis 进行数据库操作时使用。</p>
<p><strong>Spring的回滚方式</strong></p>
<p>Spring 事务的默认回滚方式是：<strong>发生运行时异常和 error 时回滚</strong>，<strong>发生受查(编译)异常时提交</strong>。不过，对于受查异常，程序员也可以手工设置其回滚方式。 </p>
<h3 id="5-1-2-事务定义接口"><a href="#5-1-2-事务定义接口" class="headerlink" title="5.1.2 事务定义接口"></a>5.1.2 事务定义接口</h3><p>事务定义接口 TransactionDefinition 中定义了事务描述相关的三类常量：事务隔离级别、事务传播行为、事务默认超时时限，及对它们的操作。</p>
<p><img src="/img%5Cimage-20210317112937181.png" class="lazyload" data-srcset="/img%5Cimage-20210317112937181.png" srcset="" alt="image-20210317112937181"></p>
<h4 id="5-1-2-1-事务隔离级别常量"><a href="#5-1-2-1-事务隔离级别常量" class="headerlink" title="5.1.2.1 事务隔离级别常量"></a>5.1.2.1 事务隔离级别常量</h4><p>这些常量均是以 ISOLATION_开头。即形如 ISOLATION_XXX。 </p>
<p>➢ DEFAULT：采用 DB 默认的事务隔离级别。MySql 的默认为 REPEATABLE_READ； Oracle默认为 READ_COMMITTED。 </p>
<p>➢ READ_UNCOMMITTED：读未提交。未解决任何并发问题。</p>
<p>➢ READ_COMMITTED：读已提交。解决脏读，存在不可重复读与幻读。</p>
<p>➢ REPEATABLE_READ：可重复读。解决脏读、不可重复读，存在幻读</p>
<p>➢ SERIALIZABLE：串行化。不存在并发问题。</p>
<h4 id="5-1-2-2-事务传播行为常量"><a href="#5-1-2-2-事务传播行为常量" class="headerlink" title="5.1.2.2 事务传播行为常量"></a>5.1.2.2 事务传播行为常量</h4><p>所谓事务传播行为是指，处于不同事务中的方法在相互调用时，执行期间事务的维护情况。如，A 事务中的方法 doSome()调用 B 事务中的方法 doOther()，在调用执行期间事务的维护情况，就称为事务传播行为。事务传播行为是加在方法上的。</p>
<p>事务传播行为常量都是以 PROPAGATION_ 开头，形如 PROPAGATION_XXX。</p>
<p>Propagation.REQUIRED</p>
<p>​		当前没有事务的时候，就会创建一个新的事务；如果当前有事务，就直接加入该事务，比较常用的设置 Propagation.SUPPORTS</p>
<p>​		支持当前事务，如果当前有事务，就直接加入该事务；当前没有事务的时候，就以非事务方式执行</p>
<p>Propagation.MANDATORY</p>
<p>​		支持当前事务，如果当前有事务，就直接加入该事务；当前没有事务的时候，就抛出异常</p>
<p> Propagation.REQUIRES_NEW</p>
<p>​		创建新事务，无论当前是否有事务都会创建新的</p>
<p>PROPAGATION_NESTED</p>
<p>PROPAGATION_NEVER</p>
<p>PROPAGATION_NOT_SUPPORTED</p>
<h4 id="5-1-2-3-默认事务超时时限"><a href="#5-1-2-3-默认事务超时时限" class="headerlink" title="5.1.2.3 默认事务超时时限"></a>5.1.2.3 默认事务超时时限</h4><p>常量 TIMEOUT_DEFAULT 定义了事务底层默认的超时时限，sql 语句的执行时长。</p>
<p>注意，事务的超时时限起作用的条件比较多，且超时的时间计算点较复杂。所以，该值一般就使用默认值即可。</p>
<h2 id="5-2-声明式事务控制"><a href="#5-2-声明式事务控制" class="headerlink" title="5.2 声明式事务控制"></a>5.2 声明式事务控制</h2><p>Spring提供的对事务的管理，就叫做声明式事务管理。</p>
<p>如果用户需要使用spring的声明式事务管理，在配置文件中配置即可：不想使用的时候直接移除配置。这种方式实现了对事务控制的最大程度的解耦。</p>
<p>声明式事务管理，核心实现就是基于AOP。</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">Spring中提供了对事务的管理。开发者只需要按照spring的方式去做就行。</span><br><span class="line">事务必须在service层统一控制。</span><br><span class="line"></span><br><span class="line">事务的粗细粒度：</span><br><span class="line">	细粒度：对方法中的某几行的代码进行开启提交回滚；</span><br><span class="line">  	粗粒度：对整个方法进行开启提交回滚；</span><br><span class="line"></span><br><span class="line">Spring中的aop只能对方法进行拦截，所有我们也就针对方法进行事务的控制。</span><br><span class="line"></span><br><span class="line">    如果只有单条的查询语句，可以省略事务；如果一次执行的是多条查询语句，例如统计结果、报表查询。必须开启事务。</span><br></pre></td></tr></table></figure>

<h2 id="5-3-基于注解的事务"><a href="#5-3-基于注解的事务" class="headerlink" title="5.3 基于注解的事务"></a>5.3 基于注解的事务</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.lina.service;</span><br><span class="line"><span class="keyword">import</span> com.lina.dao.TeamDao;</span><br><span class="line"><span class="keyword">import</span> com.lina.pojo.Team;</span><br><span class="line"><span class="keyword">import</span> org.springframework.beans.factory.annotation.Autowired;</span><br><span class="line"><span class="keyword">import</span> org.springframework.stereotype.Service;</span><br><span class="line"><span class="keyword">import</span> org.springframework.transaction.annotation.Propagation;</span><br><span class="line"><span class="keyword">import</span> org.springframework.transaction.annotation.Transactional;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Service</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">TeamService</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    <span class="keyword">private</span> TeamDao teamDao;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">	 * <span class="doctag">@Transactional</span>  属性 说明：</span></span><br><span class="line"><span class="comment">	 * readOnly:是否只读</span></span><br><span class="line"><span class="comment">	 * </span></span><br><span class="line"><span class="comment">	 * rollbackFor=&#123;Exception.class&#125;： 遇到什么异常会回滚</span></span><br><span class="line"><span class="comment">	 * </span></span><br><span class="line"><span class="comment">	 * propagation事务的传播：</span></span><br><span class="line"><span class="comment">	 * Propagation.REQUIRED:当前没有事务的时候，就会创建一个新的事务；如果当前有事务，就直接加入该事务，比较常用的设置</span></span><br><span class="line"><span class="comment">	 * Propagation.SUPPORTS:支持当前事务，如果当前有事务，就直接加入该事务；当前没有事务的时候，就以非事务方式执行</span></span><br><span class="line"><span class="comment">	 * Propagation.MANDATORY:支持当前事务，如果当前有事务，就直接加入该事务；当前没有事务的时候，就抛出异常</span></span><br><span class="line"><span class="comment">	 * Propagation.REQUIRES_NEW:创建新事务，无论当前是否有事务都会创建新的</span></span><br><span class="line"><span class="comment">	 * </span></span><br><span class="line"><span class="comment">	 * isolation=Isolation.DEFAULT：事务的隔离级别：默认是数据库的隔离级别</span></span><br><span class="line"><span class="comment">	 * </span></span><br><span class="line"><span class="comment">	 */</span></span><br><span class="line">    <span class="meta">@Transactional(propagation = Propagation.REQUIRED,rollbackFor = &#123;Exception.class&#125;)</span></span><br><span class="line">    <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">insert</span><span class="params">(Team team)</span>&#123;</span><br><span class="line">        <span class="type">int</span> num1=teamDao.insert(team);</span><br><span class="line">        System.out.println(<span class="string">&quot;第一条执行结果：num1=&quot;</span>+num1);</span><br><span class="line">        System.out.println(<span class="number">10</span>/<span class="number">0</span>);</span><br><span class="line">        <span class="type">int</span> num2=teamDao.insert(team);</span><br><span class="line">        System.out.println(<span class="string">&quot;第二条执行结果：num2=&quot;</span>+num2);</span><br><span class="line">        <span class="keyword">return</span>  num2+num1;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!--配置文件中添加context约束--&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">context:component-scan</span> <span class="attr">base-package</span>=<span class="string">&quot;com.lina&quot;</span>/&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;transactionManager&quot;</span> <span class="attr">class</span>=<span class="string">&quot;org.springframework.jdbc.datasource.DataSourceTransactionManager&quot;</span>&gt;</span></span><br><span class="line">     <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;dataSource&quot;</span> <span class="attr">ref</span>=<span class="string">&quot;dataSource&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">property</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">tx:annotation-driven</span> <span class="attr">transaction-manager</span>=<span class="string">&quot;transactionManager&quot;</span> /&gt;</span></span><br></pre></td></tr></table></figure>

<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Test</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">test01</span><span class="params">()</span>&#123;</span><br><span class="line">        ApplicationContext ac=<span class="keyword">new</span> <span class="title class_">ClassPathXmlApplicationContext</span>(<span class="string">&quot;application.xml&quot;</span>);</span><br><span class="line">        <span class="type">TeamService</span> <span class="variable">teamService</span> <span class="operator">=</span> (TeamService) ac.getBean(<span class="string">&quot;teamService&quot;</span>);</span><br><span class="line">        <span class="type">int</span> num=teamService.insert(<span class="keyword">new</span> <span class="title class_">Team</span>(<span class="string">&quot;凯尔特人&quot;</span>,<span class="string">&quot;波士顿&quot;</span>));</span><br><span class="line">        System.out.println(num);</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>

<h2 id="5-4-基于XML的事务"><a href="#5-4-基于XML的事务" class="headerlink" title="5.4 基于XML的事务"></a>5.4 基于XML的事务</h2><p>添加依赖</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">          <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.aspectj<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">          <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>aspectjweaver<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">          <span class="tag">&lt;<span class="name">version</span>&gt;</span>1.9.6<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>

<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!-- 事务管理器 --&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;transactionManager&quot;</span></span></span><br><span class="line"><span class="tag">       <span class="attr">class</span>=<span class="string">&quot;org.springframework.jdbc.datasource.DataSourceTransactionManager&quot;</span>&gt;</span></span><br><span class="line">       <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;dataSource&quot;</span> <span class="attr">ref</span>=<span class="string">&quot;dataSource&quot;</span>/&gt;</span></span><br><span class="line"> <span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">tx:advice</span> <span class="attr">id</span>=<span class="string">&quot;txAdvice&quot;</span> <span class="attr">transaction-manager</span>=<span class="string">&quot;transactionManager&quot;</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">tx:attributes</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">tx:method</span> <span class="attr">name</span>=<span class="string">&quot;insert*&quot;</span> <span class="attr">propagation</span>=<span class="string">&quot;REQUIRED&quot;</span>/&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">tx:method</span> <span class="attr">name</span>=<span class="string">&quot;add*&quot;</span> <span class="attr">propagation</span>=<span class="string">&quot;REQUIRED&quot;</span>/&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">tx:method</span> <span class="attr">name</span>=<span class="string">&quot;find*&quot;</span> <span class="attr">propagation</span>=<span class="string">&quot;SUPPORTS&quot;</span> <span class="attr">read-only</span>=<span class="string">&quot;true&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">tx:attributes</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">tx:advice</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">aop:config</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">aop:pointcut</span> <span class="attr">id</span>=<span class="string">&quot;pt&quot;</span> <span class="attr">expression</span>=<span class="string">&quot;execution(* com.lina.service..*.*(..))&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">aop:advisor</span> <span class="attr">advice-ref</span>=<span class="string">&quot;txAdvice&quot;</span>  <span class="attr">pointcut-ref</span>=<span class="string">&quot;pt&quot;</span> /&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">aop:config</span>&gt;</span></span><br></pre></td></tr></table></figure>


  </div>
  
  
    
    <div class='footer'>
       <!-- 参考资料、相关资料等 -->
      
       <!-- 相关文章 -->
      
      <!-- 版权声明组件 -->
      
      <!-- 打赏组件 -->
      
    </div>
  
  
    


  <div class='article-meta' id="bottom">
    <div class='new-meta-box'>
      
        
          <div class="new-meta-item date" itemprop="dateModified" datetime="2024-01-15T15:37:37+08:00">
  <a class='notlink'>
    <i class="fa-solid fa-edit fa-fw" aria-hidden="true"></i>
    <p>更新于：Jan 15, 2024</p>
  </a>
</div>

        
      
        
          

        
      
        
          
  <div class="new-meta-item share -mob-share-list">
  <div class="-mob-share-list share-body">
    
      
        <a class="-mob-share-qq" title="" rel="external nofollow noopener noreferrer noopener"
          
          target="_blank" href="http://connect.qq.com/widget/shareqq/index.html?url=http://8.219.11.28/2024/02/23/%E5%89%8D%E5%90%8E%E7%AB%AF-Spring%E6%A1%86%E6%9E%B6%E8%AF%BE%E5%A0%82%E7%AC%94%E8%AE%B0/&title= - 欢迎来到我的个人博客~&summary="
          
          >
          
            <img src="https://unpkg.com/volantis-static@0.0.1654736714924/media/org.volantis/logo/128/qq.png" class="lazyload" data-srcset="https://unpkg.com/volantis-static@0.0.1654736714924/media/org.volantis/logo/128/qq.png" srcset="">
          
        </a>
      
    
      
        <a class="-mob-share-qzone" title="" rel="external nofollow noopener noreferrer noopener"
          
          target="_blank" href="https://sns.qzone.qq.com/cgi-bin/qzshare/cgi_qzshare_onekey?url=http://8.219.11.28/2024/02/23/%E5%89%8D%E5%90%8E%E7%AB%AF-Spring%E6%A1%86%E6%9E%B6%E8%AF%BE%E5%A0%82%E7%AC%94%E8%AE%B0/&title= - 欢迎来到我的个人博客~&summary="
          
          >
          
            <img src="https://unpkg.com/volantis-static@0.0.1654736714924/media/org.volantis/logo/128/qzone.png" class="lazyload" data-srcset="https://unpkg.com/volantis-static@0.0.1654736714924/media/org.volantis/logo/128/qzone.png" srcset="">
          
        </a>
      
    
      
        <a class="-mob-share-weibo" title="" rel="external nofollow noopener noreferrer noopener"
          
          target="_blank" href="http://service.weibo.com/share/share.php?url=http://8.219.11.28/2024/02/23/%E5%89%8D%E5%90%8E%E7%AB%AF-Spring%E6%A1%86%E6%9E%B6%E8%AF%BE%E5%A0%82%E7%AC%94%E8%AE%B0/&title= - 欢迎来到我的个人博客~&summary="
          
          >
          
            <img src="https://unpkg.com/volantis-static@0.0.1654736714924/media/org.volantis/logo/128/weibo.png" class="lazyload" data-srcset="https://unpkg.com/volantis-static@0.0.1654736714924/media/org.volantis/logo/128/weibo.png" srcset="">
          
        </a>
      
    
      
    
      
    
  </div>
</div>



        
      
    </div>
    <!-- Custom Files bottomMeta begin -->
    
    <!-- Custom Files bottomMeta end -->
  </div>


  
  

  
    <div class="prev-next">
      
        <a class='prev' href='/2024/02/23/%E5%89%8D%E5%90%8E%E7%AB%AF-SpringMVC%E8%AF%BE%E5%A0%82%E7%AC%94%E8%AE%B0/'>
          <p class='title'><i class="fa-solid fa-chevron-left" aria-hidden="true"></i>Feb 23, 2024</p>
          <p class='content'>SpringMVC课堂笔记1、SpringMVC概述1.1 SpringMVC概念SpringMVC 也叫 Spring web mvc。是 Spring内置的一个MVC框架，在 Spring3...</p>
        </a>
      
      
        <a class='next' href='/2024/02/23/%E5%89%8D%E5%90%8E%E7%AB%AF-SpringBoot/'>
          <p class='title'>Feb 23, 2024<i class="fa-solid fa-chevron-right" aria-hidden="true"></i></p>
          <p class='content'>SpringBoot基础创建springboot的流程:1.maven 项目123456&lt;!--    所有springboot项目都必须继承自 spring-boot-starter-p...</p>
        </a>
      
    </div>
  
  <!-- Custom Files postEnd begin-->
  
  <!-- Custom Files postEnd end-->
</article>


  


  <article class="post white-box shadow floatable blur" id="comments">
    <span hidden>
      <meta itemprop="discussionUrl" content="/2024/02/23/%E5%89%8D%E5%90%8E%E7%AB%AF-Spring%E6%A1%86%E6%9E%B6%E8%AF%BE%E5%A0%82%E7%AC%94%E8%AE%B0/index.html#comments">
    </span>
    <p ct><i class='fa-solid fa-comments'></i> 评论</p>
    

    <div id="layoutHelper-comments"></div>

  </article>






</div>
<aside id='l_side' itemscope itemtype="http://schema.org/WPSideBar">
  

  
    
    
      
    
  


<div class="widget-sticky pjax">

  
  


  <section class="widget toc-wrapper desktop mobile " id="toc-div" >
    
  <header>
    
      <i class="fa-solid fa-list fa-fw" aria-hidden="true"></i><span class='name'>本文目录</span>
    
  </header>


    <div class='content'>
        <ol class="toc"><li class="toc-item toc-level-2"><a class="toc-link" href="#1-1-%E4%BB%80%E4%B9%88%E6%98%AF%E6%A1%86%E6%9E%B6%EF%BC%9F"><span class="toc-text">1.1 什么是框架？</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#1-2-Spring%E6%98%AF%E4%BB%80%E4%B9%88"><span class="toc-text">1.2 Spring是什么</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#1-3-Spring%E7%9A%84%E4%BC%98%E5%8A%BF"><span class="toc-text">1.3 Spring的优势</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#1-4-Spring%E7%9A%84%E4%BD%93%E7%B3%BB%E7%BB%93%E6%9E%84"><span class="toc-text">1.4 Spring的体系结构</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#1-4-1-%E6%A0%B8%E5%BF%83%E5%AE%B9%E5%99%A8"><span class="toc-text">1.4.1 核心容器</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#1-4-2-%E6%95%B0%E6%8D%AE%E8%AE%BF%E9%97%AE-%E9%9B%86%E6%88%90"><span class="toc-text">1.4.2 数据访问&#x2F;集成</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#1-4-3-Web"><span class="toc-text">1.4.3 Web</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#1-4-4-%E5%85%B6%E4%BB%96"><span class="toc-text">1.4.4 其他</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#2-1-IoC%E7%9A%84%E6%A6%82%E5%BF%B5"><span class="toc-text">2.1 IoC的概念</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#2-2-Spring%E5%85%A5%E9%97%A8%E6%A1%88%E4%BE%8B"><span class="toc-text">2.2 Spring入门案例</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#2-2-1-%E5%88%9B%E5%BB%BAmaven%E9%A1%B9%E7%9B%AE"><span class="toc-text">2.2.1 创建maven项目</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-2-2-pom-xml%E6%96%87%E4%BB%B6%E6%B7%BB%E5%8A%A0%E4%BE%9D%E8%B5%96%E5%92%8C%E6%8F%92%E4%BB%B6"><span class="toc-text">2.2.2 pom.xml文件添加依赖和插件</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-2-3-%E5%88%9B%E5%BB%BA%E4%B8%80%E4%B8%AA%E5%AE%9E%E4%BD%93%E7%B1%BB"><span class="toc-text">2.2.3 创建一个实体类</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-3-4-%E5%88%9B%E5%BB%BASpring%E7%9A%84%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6application-xml"><span class="toc-text">2.3.4 创建Spring的配置文件application.xml</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-3-5-%E4%BD%BF%E7%94%A8Spring%E5%AE%B9%E5%99%A8%E5%88%9B%E5%BB%BA%E5%AF%B9%E8%B1%A1"><span class="toc-text">2.3.5 使用Spring容器创建对象</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-3-6-%E8%8E%B7%E5%8F%96Spring%E5%AE%B9%E5%99%A8"><span class="toc-text">2.3.6 获取Spring容器</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#2-3-6-1-BeanFactory"><span class="toc-text">2.3.6.1 BeanFactory</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#2-3-6-2-ApplicationContext"><span class="toc-text">2.3.6.2 ApplicationContext</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#2-6-2-2-1-ClassPathXmlApplicationContext%E2%80%94%E2%80%94%E5%B8%B8%E7%94%A8"><span class="toc-text">2.6.2.2.1 ClassPathXmlApplicationContext——常用</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#2-6-2-2-2-FileSystemXmlApplicationContext"><span class="toc-text">2.6.2.2.2 FileSystemXmlApplicationContext</span></a></li></ol></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-3-7-%E9%80%9A%E8%BF%87%E4%B8%8A%E4%B8%8B%E6%96%87%E5%AF%B9%E8%B1%A1%E8%8E%B7%E5%8F%96%E5%AE%B9%E5%99%A8%E4%B8%AD%E7%9A%84%E5%AF%B9%E8%B1%A1"><span class="toc-text">2.3.7 通过上下文对象获取容器中的对象</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-3-8-%E5%88%9B%E5%BB%BA%E9%9D%9E%E8%87%AA%E5%AE%9A%E4%B9%89%E5%AF%B9%E8%B1%A1"><span class="toc-text">2.3.8 创建非自定义对象</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-3-9-bean%E6%A0%87%E7%AD%BE%E7%9A%84%E5%B1%9E%E6%80%A7"><span class="toc-text">2.3.9 bean标签的属性</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#2-3-Spring%E5%AE%B9%E5%99%A8%E5%88%9B%E5%BB%BA%E5%AF%B9%E8%B1%A1%E7%9A%84%E6%96%B9%E5%BC%8F"><span class="toc-text">2.3 Spring容器创建对象的方式</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#2-3-1-%E4%BD%BF%E7%94%A8%E9%BB%98%E8%AE%A4%E7%9A%84%E6%9E%84%E9%80%A0%E6%96%B9%E6%B3%95"><span class="toc-text">2.3.1 使用默认的构造方法</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-3-2-%E4%BD%BF%E7%94%A8%E5%B8%A6%E5%8F%82%E6%95%B0%E7%9A%84%E6%9E%84%E9%80%A0%E6%96%B9%E6%B3%95"><span class="toc-text">2.3.2 使用带参数的构造方法</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-3-3-%E4%BD%BF%E7%94%A8%E5%B7%A5%E5%8E%82%E7%B1%BB"><span class="toc-text">2.3.3 使用工厂类</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#2-4-%E5%9F%BA%E4%BA%8EXML%E7%9A%84DI"><span class="toc-text">2.4 基于XML的DI</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#2-4-1-%E6%B3%A8%E5%85%A5%E5%88%86%E7%B1%BB"><span class="toc-text">2.4.1 注入分类</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#2-4-1-1-%E9%80%9A%E8%BF%87set%E6%96%B9%E6%B3%95"><span class="toc-text">2.4.1.1 通过set方法</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#2-4-1-2-%E9%80%9A%E8%BF%87%E6%9E%84%E9%80%A0%E6%96%B9%E6%B3%95"><span class="toc-text">2.4.1.2 通过构造方法</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#2-4-1-3-%E8%87%AA%E5%8A%A8%E6%B3%A8%E5%85%A5"><span class="toc-text">2.4.1.3. 自动注入</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#1%E3%80%81-byName"><span class="toc-text">1、 byName</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#2%E3%80%81-byType"><span class="toc-text">2、 byType</span></a></li></ol></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#2-5%E3%80%81%E5%9F%BA%E4%BA%8E%E6%B3%A8%E8%A7%A3%E5%AE%9E%E7%8E%B0IoC%E2%80%93%E9%87%8D%E8%A6%81"><span class="toc-text">2.5、基于注解实现IoC–重要</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#2-5-1-%E5%A3%B0%E6%98%8EBean%E7%9A%84%E6%B3%A8%E8%A7%A3-Component"><span class="toc-text">2.5.1 声明Bean的注解 @Component</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-5-2-%E5%8C%85%E6%89%AB%E6%8F%8F"><span class="toc-text">2.5.2 包扫描</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-5-3-%E5%B1%9E%E6%80%A7%E6%B3%A8%E5%85%A5-Vaule"><span class="toc-text">2.5.3 属性注入@Vaule</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-5-4-byType%E8%87%AA%E5%8A%A8%E6%B3%A8%E5%85%A5-Autowired"><span class="toc-text">2.5.4 byType自动注入@Autowired</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-5-5-byName%E8%87%AA%E5%8A%A8%E6%B3%A8%E5%85%A5-Autowired%E5%92%8C-Qualifier"><span class="toc-text">2.5.5 byName自动注入@Autowired和@Qualifier</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-5-6-%E8%87%AA%E5%8A%A8%E6%B3%A8%E5%85%A5-Resource"><span class="toc-text">2.5.6 自动注入@Resource</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#1%E3%80%81byType%E6%B3%A8%E5%85%A5%E5%BC%95%E7%94%A8%E7%B1%BB%E5%9E%8B%E5%B1%9E%E6%80%A7"><span class="toc-text">1、byType注入引用类型属性</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#2%E3%80%81byName%E6%B3%A8%E5%85%A5%E5%BC%95%E7%94%A8%E7%B1%BB%E5%9E%8B%E5%B1%9E%E6%80%A7"><span class="toc-text">2、byName注入引用类型属性</span></a></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#3-1-%E4%BB%80%E4%B9%88%E6%98%AFAOP"><span class="toc-text">3.1 什么是AOP</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#3-2-AOP%E7%9A%84%E5%AE%9E%E7%8E%B0%E6%9C%BA%E5%88%B6-%E5%8A%A8%E6%80%81%E4%BB%A3%E7%90%86"><span class="toc-text">3.2 AOP的实现机制-动态代理</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#3-2-1-%E4%BB%80%E4%B9%88%E6%98%AF%E4%BB%A3%E7%90%86%E6%A8%A1%E5%BC%8F"><span class="toc-text">3.2.1 什么是代理模式</span></a></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#3-3%E9%9D%99%E6%80%81%E4%BB%A3%E7%90%86"><span class="toc-text">3.3静态代理</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#3-3-1-%E5%8E%9F%E6%9C%89%E6%96%B9%E5%BC%8F%EF%BC%9A%E6%A0%B8%E5%BF%83%E4%B8%9A%E5%8A%A1%E5%92%8C%E6%9C%8D%E5%8A%A1%E6%96%B9%E6%B3%95%E9%83%BD%E7%BC%96%E5%86%99%E5%9C%A8%E4%B8%80%E8%B5%B7"><span class="toc-text">3.3.1 原有方式：核心业务和服务方法都编写在一起</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#3-3-2-%E5%9F%BA%E4%BA%8E%E7%B1%BB%E7%9A%84%E9%9D%99%E6%80%81%E4%BB%A3%E7%90%86"><span class="toc-text">3.3.2 基于类的静态代理</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#3-3-3-%E5%9F%BA%E4%BA%8E%E6%8E%A5%E5%8F%A3%E7%9A%84%E9%9D%99%E6%80%81%E4%BB%A3%E7%90%86"><span class="toc-text">3.3.3 基于接口的静态代理</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#3-3-4-%E6%8F%90%E5%8F%96%E5%87%BA%E5%88%87%E9%9D%A2%E4%BB%A3%E7%A0%81%EF%BC%8C%E4%BD%9C%E4%B8%BAAOP%E6%8E%A5%E5%8F%A3"><span class="toc-text">3.3.4 提取出切面代码，作为AOP接口</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#3-4-%E5%8A%A8%E6%80%81%E4%BB%A3%E7%90%86"><span class="toc-text">3.4 动态代理</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#3-4-1-%E5%9F%BA%E4%BA%8EJDK%E7%9A%84%E5%8A%A8%E6%80%81%E4%BB%A3%E7%90%86"><span class="toc-text">3.4.1 基于JDK的动态代理</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#3-4-1-1-%E7%9B%B4%E6%8E%A5%E7%BC%96%E5%86%99%E6%B5%8B%E8%AF%95%E7%B1%BB"><span class="toc-text">3.4.1.1 直接编写测试类</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#3-4-1-2-%E7%BB%93%E6%9E%84%E5%8C%96%E8%AE%BE%E8%AE%A1"><span class="toc-text">3.4.1.2 结构化设计</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#3-4-2-%E5%9F%BA%E4%BA%8ECGLIB%E7%9A%84%E5%8A%A8%E6%80%81%E4%BB%A3%E7%90%86"><span class="toc-text">3.4.2 基于CGLIB的动态代理</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#3-4-2-1-%E7%9B%B4%E6%8E%A5%E7%BC%96%E5%86%99%E6%B5%8B%E8%AF%95%E7%B1%BB"><span class="toc-text">3.4.2.1 直接编写测试类</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#3-4-2-2-%E7%BB%93%E6%9E%84%E5%8C%96%E8%AE%BE%E8%AE%A1%E6%96%B9%E5%BC%8F"><span class="toc-text">3.4.2.2 结构化设计方式</span></a></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#3-5-SpringAOP"><span class="toc-text">3.5 SpringAOP</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#3-5-1-Spring-AOP%E7%9B%B8%E5%85%B3%E6%A6%82%E5%BF%B5"><span class="toc-text">3.5.1 Spring AOP相关概念</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#Target-%E7%9B%AE%E6%A0%87%E5%AF%B9%E8%B1%A1"><span class="toc-text">Target(目标对象)</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Proxy%EF%BC%88%E4%BB%A3%E7%90%86%EF%BC%89"><span class="toc-text">Proxy（代理）</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Aspect-%E5%88%87%E9%9D%A2"><span class="toc-text">Aspect(切面)</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Joinpoint-%E8%BF%9E%E6%8E%A5%E7%82%B9"><span class="toc-text">Joinpoint(连接点)</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Pointcut-%E5%88%87%E5%85%A5%E7%82%B9"><span class="toc-text">Pointcut(切入点)</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Advice-%E9%80%9A%E7%9F%A5-%E5%A2%9E%E5%BC%BA"><span class="toc-text">Advice(通知&#x2F;增强)</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Weaving-%E7%BB%87%E5%85%A5"><span class="toc-text">Weaving(织入).</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#3-5-2-AspectJ-%E5%AF%B9-AOP-%E7%9A%84%E5%AE%9E%E7%8E%B0"><span class="toc-text">3.5.2 AspectJ 对 AOP 的实现</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#3-5-2-1-AspectJ%E7%9A%84%E9%80%9A%E7%9F%A5%E7%B1%BB%E5%9E%8B"><span class="toc-text">3.5.2 .1 AspectJ的通知类型</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#3-5-2-2-AspectJ%E7%9A%84%E5%88%87%E5%85%A5%E7%82%B9%E8%A1%A8%E8%BE%BE%E5%BC%8F"><span class="toc-text">3.5.2.2 AspectJ的切入点表达式</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#3-5-3-%E6%B3%A8%E8%A7%A3%E6%96%B9%E5%BC%8F%E5%AE%9E%E7%8E%B0AOP"><span class="toc-text">3.5.3 注解方式实现AOP</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#3-5-4-XML%E6%96%B9%E5%BC%8F%E5%AE%9E%E7%8E%B0AOP"><span class="toc-text">3.5.4 XML方式实现AOP</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#4-1-%E4%BD%BF%E7%94%A8spring-jdbc%E6%93%8D%E4%BD%9C%E6%95%B0%E6%8D%AE%E5%BA%93"><span class="toc-text">4.1 使用spring-jdbc操作数据库</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#4-2-Spring%E7%AE%A1%E7%90%86JdbcTemplate"><span class="toc-text">4.2. Spring管理JdbcTemplate</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#5-1-Spring%E4%BA%8B%E5%8A%A1%E7%AE%A1%E7%90%86API"><span class="toc-text">5.1 Spring事务管理API</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#5-1-1-%E4%BA%8B%E5%8A%A1%E7%AE%A1%E7%90%86%E5%99%A8%E6%8E%A5%E5%8F%A3"><span class="toc-text">5.1.1 事务管理器接口</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#5-1-2-%E4%BA%8B%E5%8A%A1%E5%AE%9A%E4%B9%89%E6%8E%A5%E5%8F%A3"><span class="toc-text">5.1.2 事务定义接口</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#5-1-2-1-%E4%BA%8B%E5%8A%A1%E9%9A%94%E7%A6%BB%E7%BA%A7%E5%88%AB%E5%B8%B8%E9%87%8F"><span class="toc-text">5.1.2.1 事务隔离级别常量</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#5-1-2-2-%E4%BA%8B%E5%8A%A1%E4%BC%A0%E6%92%AD%E8%A1%8C%E4%B8%BA%E5%B8%B8%E9%87%8F"><span class="toc-text">5.1.2.2 事务传播行为常量</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#5-1-2-3-%E9%BB%98%E8%AE%A4%E4%BA%8B%E5%8A%A1%E8%B6%85%E6%97%B6%E6%97%B6%E9%99%90"><span class="toc-text">5.1.2.3 默认事务超时时限</span></a></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#5-2-%E5%A3%B0%E6%98%8E%E5%BC%8F%E4%BA%8B%E5%8A%A1%E6%8E%A7%E5%88%B6"><span class="toc-text">5.2 声明式事务控制</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#5-3-%E5%9F%BA%E4%BA%8E%E6%B3%A8%E8%A7%A3%E7%9A%84%E4%BA%8B%E5%8A%A1"><span class="toc-text">5.3 基于注解的事务</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#5-4-%E5%9F%BA%E4%BA%8EXML%E7%9A%84%E4%BA%8B%E5%8A%A1"><span class="toc-text">5.4 基于XML的事务</span></a></li></ol>
    </div>
  </section>

  

</div>


<!-- 没有 pjax 占位会报错 万恶的 pjax -->

  <div class="pjax">
    <!-- pjax占位 -->
  </div>

  <div class="pjax">
    <!-- pjax占位 -->
  </div>

  <div class="pjax">
    <!-- pjax占位 -->
  </div>

  <div class="pjax">
    <!-- pjax占位 -->
  </div>

  <div class="pjax">
    <!-- pjax占位 -->
  </div>

  <div class="pjax">
    <!-- pjax占位 -->
  </div>

  <div class="pjax">
    <!-- pjax占位 -->
  </div>

  <div class="pjax">
    <!-- pjax占位 -->
  </div>

  <!-- Custom Files side begin -->
  
  <!-- Custom Files side end -->
</aside>



          <!--此文件用来存放一些不方便取值的变量-->
<!--思路大概是将值藏到重加载的区域内-->

<pjax>
<script>
  window.pdata={}
  pdata.ispage=false;
  pdata.commentPath="";
  pdata.commentPlaceholder="";
  pdata.commentConfig={};
  //  see: /layout/_partial/scripts/_ctrl/coverCtrl.ejs
  
    // header
    var l_header=document.getElementById("l_header");
    
    l_header.classList.add("show");
    
    
      // cover
      var cover_wrapper=document.querySelector('#l_cover .cover-wrapper');
      var scroll_down=document.getElementById('scroll-down');
      cover_wrapper.id="none";
      cover_wrapper.style.display="none";
      scroll_down.style.display="none";
    
  
</script>
</pjax>
        </div>
        
  
  <footer class="footer clearfix"  itemscope itemtype="http://schema.org/WPFooter">
    <br><br>
    
      
        <div class="aplayer-container">
          


        </div>
      
    
      
        <br>
        <div class="social-wrapper" itemprop="about" itemscope itemtype="http://schema.org/Thing">
          
            
          
            
          
            
          
        </div>
      
    
      
        <div><p>Blog content follows the <a target="_blank" rel="noopener" href="https://creativecommons.org/licenses/by-nc-sa/4.0/deed.en">Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0) License</a></p>
</div>
      
    
      
        
          <div><p><span id="lc-sv">本站总访问量为 <span id='number'><i class="fa-solid fa-loader fa-spin fa-fw" aria-hidden="true"></i></span> 次</span> <span id="lc-uv">访客数为 <span id='number'><i class="fa-solid fa-loader fa-spin fa-fw" aria-hidden="true"></i></span> 人</span></p>
</div>
        
      
    
      
        Use
        <a href="https://github.com/volantis-x/hexo-theme-volantis/#5.8.0" target="_blank" class="codename">Volantis</a>
        as theme
      
    
      
        <div class='copyright'>
        <p><a href="/">Copyright © since 2017 XXX</a></p>

        </div>
      
    
    <!-- Custom Files footer begin-->
    
    <!-- Custom Files footer end-->
  </footer>


        <a id="s-top" class="fa-solid fa-arrow-up fa-fw" href="/" onclick="return false;" title="top"></a>
      </div>
    </div>
    <div>
      <script>
  /******************** volantis.dom ********************************/
  // 页面选择器 将dom对象缓存起来 see: /source/js/app.js etc.
  volantis.dom.bodyAnchor = volantis.dom.$(document.getElementById("safearea")); // 页面主体
  volantis.dom.topBtn = volantis.dom.$(document.getElementById('s-top')); // 向上
  volantis.dom.wrapper = volantis.dom.$(document.getElementById('wrapper')); // 整个导航栏
  volantis.dom.coverAnchor = volantis.dom.$(document.querySelector('#l_cover .cover-wrapper')); // 1个
  volantis.dom.switcher = volantis.dom.$(document.querySelector('#l_header .switcher .s-search')); // 搜索按钮   移动端 1个
  volantis.dom.header = volantis.dom.$(document.getElementById('l_header')); // 移动端导航栏
  volantis.dom.search = volantis.dom.$(document.querySelector('#l_header .m_search')); // 搜索框 桌面端 移动端 1个
  volantis.dom.mPhoneList = volantis.dom.$(document.querySelectorAll('#l_header .m-phone .list-v')); //  手机端 子菜单 多个
</script>

<script>
  
  volantis.css("https://unpkg.com/volantis-static@0.0.1654736714924/libs/@fortawesome/fontawesome-free/css/all.min.css");
  
  
  
</script>

<!-- required -->


<!-- internal -->

<script src="/js/app.js"></script>






<!-- rightmenu要在darkmode之前（ToggleButton） darkmode要在comments之前（volantis.dark.push）-->



<script>
  function loadIssuesJS() {
    
      const sites_api = document.getElementById('sites-api');
      if (sites_api != undefined && typeof SitesJS === 'undefined') {
        volantis.js("/js/plugins/tags/sites.js")
      }
    
    
      const friends_api = document.getElementById('friends-api');
      if (friends_api != undefined && typeof FriendsJS === 'undefined') {
        volantis.js("/js/plugins/tags/friends.js")
      }
    
    
      const contributors_api = document.getElementById('contributors-api');
      if (contributors_api != undefined && typeof ContributorsJS === 'undefined') {
        volantis.js("/js/plugins/tags/contributors.js")
      }
    
  };
  loadIssuesJS()
  volantis.pjax.push(()=>{
    loadIssuesJS();
  })

</script>




  <script defer src="https://unpkg.com/volantis-static@0.0.1654736714924/libs/vanilla-lazyload/dist/lazyload.min.js"></script>
<script>
  // https://www.npmjs.com/package/vanilla-lazyload
  // Set the options globally
  // to make LazyLoad self-initialize
  window.lazyLoadOptions = {
    elements_selector: ".lazyload",
    threshold: 0
  };
  // Listen to the initialization event
  // and get the instance of LazyLoad
  window.addEventListener(
    "LazyLoad::Initialized",
    function (event) {
      window.lazyLoadInstance = event.detail.instance;
    },
    false
  );
  document.addEventListener('DOMContentLoaded', function () {
    lazyLoadInstance.update();
  });
  document.addEventListener('pjax:complete', function () {
    lazyLoadInstance.update();
  });
</script>




  

<script>
  window.FPConfig = {
	delay: 0,
	ignoreKeywords: ["#"],
	maxRPS: 6,
	hoverDelay: 0
  };
</script>
<script defer src="https://unpkg.com/volantis-static@0.0.1654736714924/libs/flying-pages/flying-pages.min.js"></script>









      <script>
  volantis.layoutHelper("comments",`<div id="giscus_container"></div>`)

  volantis.giscus = {};

  function check_giscus() {
    if (volantis.dark.mode === "dark") {
      volantis.giscus.Theme = 'dark';
    } else {
      volantis.giscus.Theme = 'light';
    }

    return document.getElementById("giscus_container");
  }

  function pjax_giscus() {
    const HEAD = check_giscus();
    if (!HEAD) return;
    let cfg = Object.assign({"theme":{"light":"light","dark":"dark"}},pdata.commentConfig)
    const script = document.createElement('script');
    script.setAttribute('src', 'https://giscus.app/client.js');
    Object.keys(cfg).forEach(k=>{
      if (k != "theme") {
        script.setAttribute('data-'+k, cfg[k]);
      }
    })
    script.setAttribute('data-theme', volantis.giscus.Theme);
    script.setAttribute('crossorigin', "anonymous");
    HEAD.appendChild(script);
  }

  function dark_giscus() {
    const HEAD = check_giscus();
    if (!HEAD) return;

    const message = {
      setConfig: {
        theme: volantis.giscus.Theme
      }
    };
    const giscusIframe = document.querySelector('iframe.giscus-frame');
    giscusIframe.contentWindow.postMessage({ giscus: message }, 'https://giscus.app');
  }
  pjax_giscus();
  volantis.pjax.push(pjax_giscus);
  volantis.dark.push(dark_giscus);
</script>

    





<!-- optional -->

  <script>
  const SearchServiceDataPathRoot = ("/" || "/").endsWith("/") ?
    "/" || "/" :
    "//" || "/";
  const SearchServiceDataPath = SearchServiceDataPathRoot + "content.json";

  function loadSearchScript() {
    // see: layout/_partial/scripts/_ctrl/cdnCtrl.ejs
    return volantis.js("/js/search/hexo.js");
  }

  function loadSearchService() {
    loadSearchScript();
    document.querySelectorAll(".input.u-search-input").forEach((e) => {
      e.removeEventListener("focus", loadSearchService, false);
    });

    document.querySelectorAll(".u-search-form").forEach((e) => {
      e.addEventListener("submit", (event) => {
        event.preventDefault();
      }, false);
    });
  }

  // 打开并搜索 字符串 s
  function OpenSearch(s) {
    if (typeof SearchService === 'undefined')
      loadSearchScript().then(() => {
        SearchService.setQueryText(s);
        SearchService.search();
      });
    else {
      SearchService.setQueryText(s);
      SearchService.search();
    }
  }

  // 访问含有 ?s=xxx  的链接时打开搜索 // 与搜索引擎 structured data 相关: /scripts/helpers/structured-data/lib/config.js
  if (window.location.search && /^\?s=/g.test(window.location.search)) {
    let queryText = decodeURI(window.location.search)
      .replace(/\ /g, "-")
      .replace(/^\?s=/g, "");
    OpenSearch(queryText);
  }

  // 搜索输入框获取焦点时加载搜索
  document.querySelectorAll(".input.u-search-input").forEach((e) => {
    e.addEventListener("focus", loadSearchService, false);
  });
</script>







  <script>



  function pjax_highlightjs_copyCode(){
    if (!(document.querySelector(".highlight .code pre") ||
      document.querySelector(".article pre code"))) {
      return;
    }
    VolantisApp.utilCopyCode(".highlight .code pre, .article pre code")
  }
  volantis.requestAnimationFrame(pjax_highlightjs_copyCode)
  volantis.pjax.push(pjax_highlightjs_copyCode)

</script>












  <script>
  function load_swiper() {
    if (!document.querySelectorAll(".swiper-container")[0]) return;
    volantis.css("https://unpkg.com/volantis-static@0.0.1654736714924/libs/swiper/swiper-bundle.min.css");
    volantis.js("https://unpkg.com/volantis-static@0.0.1654736714924/libs/swiper/swiper-bundle.min.js").then(() => {
      pjax_swiper();
    });
  }

  load_swiper();

  function pjax_swiper() {
    volantis.swiper = new Swiper('.swiper-container', {
      slidesPerView: 'auto',
      spaceBetween: 8,
      centeredSlides: true,
      loop: true,
      pagination: {
        el: '.swiper-pagination',
        clickable: true,
      },
      navigation: {
        nextEl: '.swiper-button-next',
        prevEl: '.swiper-button-prev',
      },
    });
  }

  volantis.pjax.push(() => {
    if (!document.querySelectorAll(".swiper-container")[0]) return;
    if (typeof volantis.swiper === "undefined") {
      load_swiper();
    } else {
      pjax_swiper();
    }
  });
</script>


<!-- pjax 标签必须存在于所有页面 否则 pjax error -->
<pjax>

</pjax>

<script>
  function listennSidebarTOC() {
    const navItems = document.querySelectorAll(".toc li");
    if (!navItems.length) return;
    let targets = []
    const sections = [...navItems].map((element) => {
      const link = element.querySelector(".toc-link");
      const target = document.getElementById(
        decodeURI(link.getAttribute("href")).replace("#", "")
      );
      targets.push(target)
      // 解除 a 标签 href 的 锚点定位, a 标签 href 的 锚点定位 会随机启用?? 产生错位???
      link.setAttribute("onclick","return false;")
      link.setAttribute("toc-action","toc-"+decodeURI(link.getAttribute("href")).replace("#", ""))
      link.setAttribute("href","/")
      // 配置 点击 触发新的锚点定位
      link.addEventListener("click", (event) => {
        event.preventDefault();
        // 这里的 addTop 是通过错位使得 toc 自动展开.
        volantis.scroll.to(target,{addTop: 5, observer:true})
        // Anchor id
        history.pushState(null, document.title, "#" + target.id);
      });
      return target;
    });

    function activateNavByIndex(target) {
      if (target.classList.contains("active-current")) return;

      document.querySelectorAll(".toc .active").forEach((element) => {
        element.classList.remove("active", "active-current");
      });
      target.classList.add("active", "active-current");
      let parent = target.parentNode;
      while (!parent.matches(".toc")) {
        if (parent.matches("li")) parent.classList.add("active");
        parent = parent.parentNode;
      }
    }

    // 方案一：
    volantis.activateNavIndex=0
    activateNavByIndex(navItems[volantis.activateNavIndex])
    volantis.scroll.push(()=>{
      if (targets[0].getBoundingClientRect().top >= 0) {
        volantis.activateNavIndex = 0
      }else if (targets[targets.length-1].getBoundingClientRect().top < 0) {
        volantis.activateNavIndex = targets.length-1
      } else {
        for (let index = 0; index < targets.length; index++) {
          const target0 = targets[index];
          const target1 = targets[(index+1)%targets.length];
          if (target0.getBoundingClientRect().top < 0&&target1.getBoundingClientRect().top >= 0) {
            volantis.activateNavIndex=index
            break;
          }
        }
      }
      activateNavByIndex(navItems[volantis.activateNavIndex])
    })

    // 方案二：
    // IntersectionObserver 不是完美精确到像素级别 也不是低延时性的
    // function findIndex(entries) {
    //   let index = 0;
    //   let entry = entries[index];
    //   if (entry.boundingClientRect.top > 0) {
    //     index = sections.indexOf(entry.target);
    //     return index === 0 ? 0 : index - 1;
    //   }
    //   for (; index < entries.length; index++) {
    //     if (entries[index].boundingClientRect.top <= 0) {
    //       entry = entries[index];
    //     } else {
    //       return sections.indexOf(entry.target);
    //     }
    //   }
    //   return sections.indexOf(entry.target);
    // }
    // function createIntersectionObserver(marginTop) {
    //   marginTop = Math.floor(marginTop + 10000);
    //   let intersectionObserver = new IntersectionObserver(
    //     (entries, observe) => {
    //       let scrollHeight = document.documentElement.scrollHeight;
    //       if (scrollHeight > marginTop) {
    //         observe.disconnect();
    //         createIntersectionObserver(scrollHeight);
    //         return;
    //       }
    //       let index = findIndex(entries);
    //       activateNavByIndex(navItems[index]);
    //     }, {
    //       rootMargin: marginTop + "px 0px -100% 0px",
    //       threshold: 0,
    //     }
    //   );
    //   sections.forEach((element) => {
    //     element && intersectionObserver.observe(element);
    //   });
    // }
    // createIntersectionObserver(document.documentElement.scrollHeight);
  }

  document.addEventListener("DOMContentLoaded", ()=>{
    volantis.requestAnimationFrame(listennSidebarTOC)
  });
  document.addEventListener("pjax:success", ()=>{
    volantis.requestAnimationFrame(listennSidebarTOC)
  });
</script>



<script>
  document.onreadystatechange = function () {
    if (document.readyState == 'complete') {
      // 页面加载完毕 样式加载失败，或是当前网速慢，或是开启了省流模式
      const { saveData, effectiveType } = navigator.connection || navigator.mozConnection || navigator.webkitConnection || {}
      if (getComputedStyle(document.querySelector("#safearea"), null)["display"] == "none" || saveData || /2g/.test(effectiveType)) {
        document.querySelectorAll(".reveal").forEach(function (e) {
          e.style["opacity"] = "1";
        });
        document.querySelector("#safearea").style["display"] = "block";
      }
    }
  }
</script>


  <script type="application/ld+json">[{"@context":"http://schema.org","@type":"Organization","name":"欢迎来到我的个人博客~","url":"http://8.219.11.28/","logo":{"@type":"ImageObject","url":"https://unpkg.com/volantis-static@0.0.1654736714924/media/org.volantis/blog/favicon/android-chrome-192x192.png","width":192,"height":192}},{"@context":"http://schema.org","@type":"Person","name":"天明","image":{"@type":"ImageObject","url":"https://unpkg.com/volantis-static@0.0.1654736714924/media/org.volantis/blog/favicon/android-chrome-192x192.png"},"url":"http://8.219.11.28/","sameAs":["https://github.com/volantis-x"],"description":"这些技术大部分是自己总结的，非官方"},{"@context":"http://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"http://8.219.11.28/","name":"欢迎来到我的个人博客~"}},{"@type":"ListItem","position":3,"item":{"@id":"http://8.219.11.28/2024/02/23/前后端-Spring框架课堂笔记/"}}]},{"@context":"http://schema.org","@type":"WebSite","name":"欢迎来到我的个人博客~","url":"http://8.219.11.28/","keywords":null,"description":"这些技术大部分是自己总结的，非官方","author":{"@type":"Person","name":"天明","image":{"@type":"ImageObject","url":"https://unpkg.com/volantis-static@0.0.1654736714924/media/org.volantis/blog/favicon/android-chrome-192x192.png"},"url":"http://8.219.11.28/","description":"这些技术大部分是自己总结的，非官方"},"publisher":{"@type":"Organization","name":"欢迎来到我的个人博客~","url":"http://8.219.11.28/","logo":{"@type":"ImageObject","url":"https://unpkg.com/volantis-static@0.0.1654736714924/media/org.volantis/blog/favicon/android-chrome-192x192.png","width":192,"height":192}},"potentialAction":{"@type":"SearchAction","name":"Site Search","target":{"@type":"EntryPoint","urlTemplate":"http://8.219.11.28?s={search_term_string}"},"query-input":"required name=search_term_string"}},{"@context":"http://schema.org","@type":"BlogPosting","description":"这些技术大部分是自己总结的，非官方","inLanguage":"en","mainEntityOfPage":{"@type":"WebPage","@id":"http://8.219.11.28/2024/02/23/%E5%89%8D%E5%90%8E%E7%AB%AF-Spring%E6%A1%86%E6%9E%B6%E8%AF%BE%E5%A0%82%E7%AC%94%E8%AE%B0/"},"author":{"@type":"Person","name":"天明","image":{"@type":"ImageObject","url":"https://unpkg.com/volantis-static@0.0.1654736714924/media/org.volantis/blog/favicon/android-chrome-192x192.png"},"url":"http://8.219.11.28/"},"publisher":{"@type":"Organization","name":"欢迎来到我的个人博客~","logo":{"@type":"ImageObject","url":"https://unpkg.com/volantis-static@0.0.1654736714924/media/org.volantis/blog/favicon/android-chrome-192x192.png","width":192,"height":192}},"url":"http://8.219.11.28/2024/02/23/%E5%89%8D%E5%90%8E%E7%AB%AF-Spring%E6%A1%86%E6%9E%B6%E8%AF%BE%E5%A0%82%E7%AC%94%E8%AE%B0/","wordCount":0,"datePublished":"2024-02-23T14:27:45.499Z","dateModified":"2024-01-15T07:37:37.973Z","image":{"@type":"ImageObject","url":"https://unpkg.com/volantis-static@0.0.1654736714924/media/org.volantis/blog/favicon/android-chrome-192x192.png","width":192,"height":192}}]</script>



      
        <!--
  pjax重载区域接口：
  1.  <pjax></pjax> 标签 pjax 标签必须存在于所有页面 否则 pjax error
  2.  script[data-pjax]
  3.  .pjax-reload script
  4.  .pjax
-->



<script src="https://unpkg.com/volantis-static@0.0.1654736714924/libs/pjax/pjax.min.js"></script>


<script>
    var pjax;
    document.addEventListener('DOMContentLoaded', function () {
      pjax = new Pjax({
        elements: 'a[href]:not([href^="#"]):not([href="javascript:void(0)"]):not([pjax-fancybox]):not([onclick="return false;"]):not([onclick="return!1"]):not([target="_blank"]):not([target="view_window"]):not([href$=".xml"])',
        selectors: [
          "head title",
          "head meta[name=keywords]",
          "head meta[name=description]",
          
          "#l_main",
          "#pjax-header-nav-list",
          ".pjax",
          "pjax", // <pjax></pjax> 标签
          "script[data-pjax], .pjax-reload script" // script标签添加data-pjax 或 script标签外层添加.pjax-reload 的script代码段重载
        ],
        cacheBust: false,   // url 地址追加时间戳，用以避免浏览器缓存
        timeout: 5000,
        
      });
    });

    document.addEventListener('pjax:send', function (e) {
      //window.stop(); // 相当于点击了浏览器的停止按钮

      try {
        var currentUrl = window.location.pathname;
        var targetUrl = e.triggerElement.href;
        var banUrl = [""];
        if (banUrl[0] != "") {
          banUrl.forEach(item => {
            if(currentUrl.indexOf(item) != -1 || targetUrl.indexOf(item) != -1) {
              window.location.href = targetUrl;
            }
          });
        }
      } catch (error) {}

      // 使用 volantis.pjax.send 方法传入pjax:send回调函数 参见layout/_partial/scripts/global.ejs
      volantis.pjax.method.send.start();
    });

    document.addEventListener('pjax:complete', function () {
      // 使用 volantis.pjax.push 方法传入重载函数 参见layout/_partial/scripts/global.ejs
      volantis.pjax.method.complete.start();
    });

    document.addEventListener('pjax:error', function (e) {
      if(volantis.debug) {
        console.error(e);
        console.log('pjax error: \n' + JSON.stringify(e));
      }else{
        // 使用 volantis.pjax.error 方法传入pjax:error回调函数 参见layout/_partial/scripts/global.ejs
        volantis.pjax.method.error.start();
        window.location.href = e.triggerElement.href;
      }
    });
</script>

      
    </div>
    <!-- import body_end begin-->
    <!-- import body_end end-->
    <!-- Custom Files bodyEnd begin-->
    
    <!-- Custom Files bodyEnd end-->
    <!-- front-matter body_end begin -->
    <!-- front-matter body_end end -->
  </body>
</html>
